blob: 9c6cf2dfdb27569127cb135ccae4fb8e298bae55 [file] [log] [blame]
Daniel Veillard6eadf632003-01-23 18:29:16 +00001/*
2 * relaxng.c : implementation of the Relax-NG handling and validity checking
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <veillard@redhat.com>
7 */
8
Daniel Veillardd41f4f42003-01-29 21:07:52 +00009/**
10 * TODO:
Daniel Veillardf4b4f982003-02-13 11:02:08 +000011 * - add support for DTD compatibility spec
12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardac297932003-04-17 12:55:35 +000013 * - report better mem allocations pbms at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000014 */
15
Daniel Veillard6eadf632003-01-23 18:29:16 +000016#define IN_LIBXML
17#include "libxml.h"
18
19#ifdef LIBXML_SCHEMAS_ENABLED
20
21#include <string.h>
22#include <stdio.h>
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25#include <libxml/parserInternals.h>
26#include <libxml/hash.h>
27#include <libxml/uri.h>
28
29#include <libxml/relaxng.h>
30
31#include <libxml/xmlschemastypes.h>
32#include <libxml/xmlautomata.h>
33#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000034#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000035
36/*
37 * The Relax-NG namespace
38 */
39static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40 "http://relaxng.org/ns/structure/1.0";
41
42#define IS_RELAXNG(node, type) \
43 ((node != NULL) && (node->ns != NULL) && \
44 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
45 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
46
47
Daniel Veillard952379b2003-03-17 15:37:12 +000048/* #define DEBUG 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000049
Daniel Veillardc482e262003-02-26 14:48:48 +000050/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000051
Daniel Veillard71531f32003-02-05 13:19:53 +000052/* #define DEBUG_CONTENT 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000053
Daniel Veillard71531f32003-02-05 13:19:53 +000054/* #define DEBUG_TYPE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000055
Daniel Veillard71531f32003-02-05 13:19:53 +000056/* #define DEBUG_VALID 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000057
Daniel Veillarde5b110b2003-02-04 14:43:39 +000058/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000059
Daniel Veillard416589a2003-02-17 17:25:42 +000060/* #define DEBUG_LIST 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000061
Daniel Veillard5add8682003-03-10 13:13:58 +000062/* #define DEBUG_INCLUDE */
Daniel Veillard4c004142003-10-07 11:33:24 +000063
Daniel Veillarda507fbf2003-03-31 16:09:37 +000064/* #define DEBUG_ERROR 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000065
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000066/* #define DEBUG_COMPILE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000067
Daniel Veillardf4e55762003-04-15 23:32:22 +000068/* #define DEBUG_PROGRESSIVE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000069
Daniel Veillard5f1946a2003-03-31 16:38:16 +000070#define MAX_ERROR 5
71
Daniel Veillard6eadf632003-01-23 18:29:16 +000072#define TODO \
73 xmlGenericError(xmlGenericErrorContext, \
74 "Unimplemented block at %s:%d\n", \
75 __FILE__, __LINE__);
76
77typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
78typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
79
80typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
81typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
82
Daniel Veillardd41f4f42003-01-29 21:07:52 +000083typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
84typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
85
Daniel Veillarda9d912d2003-02-01 17:43:10 +000086typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
87typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
88
Daniel Veillard6eadf632003-01-23 18:29:16 +000089typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +000090 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
91 XML_RELAXNG_COMBINE_CHOICE, /* choice */
92 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
Daniel Veillard6eadf632003-01-23 18:29:16 +000093} xmlRelaxNGCombine;
94
Daniel Veillard4c5cf702003-02-21 15:40:34 +000095typedef enum {
96 XML_RELAXNG_CONTENT_ERROR = -1,
97 XML_RELAXNG_CONTENT_EMPTY = 0,
98 XML_RELAXNG_CONTENT_SIMPLE,
99 XML_RELAXNG_CONTENT_COMPLEX
100} xmlRelaxNGContentType;
101
Daniel Veillard6eadf632003-01-23 18:29:16 +0000102typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
103typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
104
105struct _xmlRelaxNGGrammar {
Daniel Veillard4c004142003-10-07 11:33:24 +0000106 xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
107 xmlRelaxNGGrammarPtr children; /* the children grammar if any */
108 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
109 xmlRelaxNGDefinePtr start; /* <start> content */
110 xmlRelaxNGCombine combine; /* the default combine value */
111 xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
112 xmlHashTablePtr defs; /* define* */
113 xmlHashTablePtr refs; /* references */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114};
115
116
Daniel Veillard6eadf632003-01-23 18:29:16 +0000117typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +0000118 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
119 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000120 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard4c004142003-10-07 11:33:24 +0000121 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
122 XML_RELAXNG_TEXT, /* textual content */
123 XML_RELAXNG_ELEMENT, /* an element */
124 XML_RELAXNG_DATATYPE, /* extenal data type definition */
125 XML_RELAXNG_PARAM, /* extenal data type parameter */
126 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
127 XML_RELAXNG_LIST, /* a list of patterns */
128 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
129 XML_RELAXNG_DEF, /* a definition */
130 XML_RELAXNG_REF, /* reference to a definition */
131 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
132 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
133 XML_RELAXNG_OPTIONAL, /* optional patterns */
134 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
135 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
136 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
137 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
138 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
139 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000140} xmlRelaxNGType;
141
Daniel Veillard52b48c72003-04-13 19:53:42 +0000142#define IS_NULLABLE (1 << 0)
143#define IS_NOT_NULLABLE (1 << 1)
144#define IS_INDETERMINIST (1 << 2)
145#define IS_MIXED (1 << 3)
146#define IS_TRIABLE (1 << 4)
147#define IS_PROCESSED (1 << 5)
148#define IS_COMPILABLE (1 << 6)
149#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000150
Daniel Veillard6eadf632003-01-23 18:29:16 +0000151struct _xmlRelaxNGDefine {
Daniel Veillard4c004142003-10-07 11:33:24 +0000152 xmlRelaxNGType type; /* the type of definition */
153 xmlNodePtr node; /* the node in the source */
154 xmlChar *name; /* the element local name if present */
155 xmlChar *ns; /* the namespace local name if present */
156 xmlChar *value; /* value when available */
157 void *data; /* data lib or specific pointer */
158 xmlRelaxNGDefinePtr content; /* the expected content */
159 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
160 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
161 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
162 xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
163 xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
164 short depth; /* used for the cycle detection */
165 short dflags; /* define related flags */
166 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000167};
168
169/**
170 * _xmlRelaxNG:
171 *
172 * A RelaxNGs definition
173 */
174struct _xmlRelaxNG {
Daniel Veillard4c004142003-10-07 11:33:24 +0000175 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000176 xmlRelaxNGGrammarPtr topgrammar;
177 xmlDocPtr doc;
178
Daniel Veillard4c004142003-10-07 11:33:24 +0000179 int idref; /* requires idref checking */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000180
Daniel Veillard4c004142003-10-07 11:33:24 +0000181 xmlHashTablePtr defs; /* define */
182 xmlHashTablePtr refs; /* references */
183 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
184 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
185 int defNr; /* number of defines used */
186 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000187
Daniel Veillard6eadf632003-01-23 18:29:16 +0000188};
189
Daniel Veillard77648bb2003-02-20 15:03:22 +0000190#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
191#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
192#define XML_RELAXNG_IN_LIST (1 << 2)
193#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
194#define XML_RELAXNG_IN_START (1 << 4)
195#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
196#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
197#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000198#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
199#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200
201struct _xmlRelaxNGParserCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000202 void *userData; /* user specific data block */
203 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
204 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000205 xmlStructuredErrorFunc serror;
Daniel Veillard42f12e92003-03-07 18:32:59 +0000206 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000207
Daniel Veillard4c004142003-10-07 11:33:24 +0000208 xmlRelaxNGPtr schema; /* The schema in use */
209 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
210 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
211 int flags; /* parser flags */
212 int nbErrors; /* number of errors at parse time */
213 int nbWarnings; /* number of warnings at parse time */
214 const xmlChar *define; /* the current define scope */
215 xmlRelaxNGDefinePtr def; /* the current define */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000216
Daniel Veillard4c004142003-10-07 11:33:24 +0000217 int nbInterleaves;
218 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000219
Daniel Veillard4c004142003-10-07 11:33:24 +0000220 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
221 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
222 xmlChar *URL;
223 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000224
Daniel Veillard4c004142003-10-07 11:33:24 +0000225 int defNr; /* number of defines used */
226 int defMax; /* number of defines aloocated */
227 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard419a7682003-02-03 23:22:49 +0000228
Daniel Veillard4c004142003-10-07 11:33:24 +0000229 const char *buffer;
230 int size;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000231
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000232 /* the document stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000233 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
234 int docNr; /* Depth of the parsing stack */
235 int docMax; /* Max depth of the parsing stack */
236 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000237
238 /* the include stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000239 xmlRelaxNGIncludePtr inc; /* Current parsed include */
240 int incNr; /* Depth of the include parsing stack */
241 int incMax; /* Max depth of the parsing stack */
242 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000243
Daniel Veillard4c004142003-10-07 11:33:24 +0000244 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000245
246 /* used to compile content models */
Daniel Veillard4c004142003-10-07 11:33:24 +0000247 xmlAutomataPtr am; /* the automata */
248 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard03c2f0a2004-01-25 19:54:59 +0000249
250 int crng; /* compact syntax and other flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000251};
252
253#define FLAGS_IGNORABLE 1
254#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000255#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000256
257/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000258 * xmlRelaxNGInterleaveGroup:
259 *
260 * A RelaxNGs partition set associated to lists of definitions
261 */
262typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
263typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
264struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000265 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
266 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
267 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000268};
269
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000270#define IS_DETERMINIST 1
271#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000272
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000273/**
274 * xmlRelaxNGPartitions:
275 *
276 * A RelaxNGs partition associated to an interleave group
277 */
278typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
279typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
280struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000281 int nbgroups; /* number of groups in the partitions */
282 xmlHashTablePtr triage; /* hash table used to direct nodes to the
283 * right group when possible */
284 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000285 xmlRelaxNGInterleaveGroupPtr *groups;
286};
287
288/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000289 * xmlRelaxNGValidState:
290 *
291 * A RelaxNGs validation state
292 */
293#define MAX_ATTR 20
294typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
295typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
296struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000297 xmlNodePtr node; /* the current node */
298 xmlNodePtr seq; /* the sequence of children left to validate */
299 int nbAttrs; /* the number of attributes */
300 int maxAttrs; /* the size of attrs */
301 int nbAttrLeft; /* the number of attributes left to validate */
302 xmlChar *value; /* the value when operating on string */
303 xmlChar *endvalue; /* the end value when operating on string */
304 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000305};
306
307/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000308 * xmlRelaxNGStates:
309 *
310 * A RelaxNGs container for validation state
311 */
312typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
313typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
314struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000315 int nbState; /* the number of states */
316 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000317 xmlRelaxNGValidStatePtr *tabState;
318};
319
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000320#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000321
Daniel Veillardfd573f12003-03-16 17:52:32 +0000322/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000323 * xmlRelaxNGValidError:
324 *
325 * A RelaxNGs validation error
326 */
327typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
328typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
329struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000330 xmlRelaxNGValidErr err; /* the error number */
331 int flags; /* flags */
332 xmlNodePtr node; /* the current node */
333 xmlNodePtr seq; /* the current child */
334 const xmlChar *arg1; /* first arg */
335 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000336};
337
338/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000339 * xmlRelaxNGValidCtxt:
340 *
341 * A RelaxNGs validation context
342 */
343
344struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000345 void *userData; /* user specific data block */
346 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
347 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000348 xmlStructuredErrorFunc serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000349 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000350
Daniel Veillard4c004142003-10-07 11:33:24 +0000351 xmlRelaxNGPtr schema; /* The schema in use */
352 xmlDocPtr doc; /* the document being validated */
353 int flags; /* validation flags */
354 int depth; /* validation depth */
355 int idref; /* requires idref checking */
356 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000357
358 /*
359 * Errors accumulated in branches may have to be stacked to be
360 * provided back when it's sure they affect validation.
361 */
362 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000363 int errNr; /* Depth of the error stack */
364 int errMax; /* Max depth of the error stack */
365 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000366
Daniel Veillard4c004142003-10-07 11:33:24 +0000367 xmlRelaxNGValidStatePtr state; /* the current validation state */
368 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000369
Daniel Veillard4c004142003-10-07 11:33:24 +0000370 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
371 int freeStatesNr;
372 int freeStatesMax;
373 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000374
375 /*
376 * This is used for "progressive" validation
377 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000378 xmlRegExecCtxtPtr elem; /* the current element regexp */
379 int elemNr; /* the number of element validated */
380 int elemMax; /* the max depth of elements */
381 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
382 int pstate; /* progressive state */
383 xmlNodePtr pnode; /* the current node */
384 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
385 int perr; /* signal error in content model
386 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000387};
388
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000389/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000390 * xmlRelaxNGInclude:
391 *
392 * Structure associated to a RelaxNGs document element
393 */
394struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000395 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
396 xmlChar *href; /* the normalized href value */
397 xmlDocPtr doc; /* the associated XML document */
398 xmlRelaxNGDefinePtr content; /* the definitions */
399 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000400};
401
402/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000403 * xmlRelaxNGDocument:
404 *
405 * Structure associated to a RelaxNGs document element
406 */
407struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000408 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000409 xmlChar *href; /* the normalized href value */
410 xmlDocPtr doc; /* the associated XML document */
411 xmlRelaxNGDefinePtr content; /* the definitions */
412 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000413};
414
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000415
Daniel Veillard6eadf632003-01-23 18:29:16 +0000416/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000417 * *
418 * Some factorized error routines *
419 * *
420 ************************************************************************/
421
422/**
423 * xmlRngPErrMemory:
424 * @ctxt: an Relax-NG parser context
425 * @extra: extra informations
426 *
427 * Handle a redefinition of attribute error
428 */
429static void
430xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
431{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000432 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000433 xmlGenericErrorFunc channel = NULL;
434 void *data = NULL;
435
436 if (ctxt != NULL) {
437 channel = ctxt->error;
438 data = ctxt->userData;
439 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000440 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000441 }
442 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000443 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000444 NULL, NULL, XML_FROM_RELAXNGP,
445 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
446 NULL, NULL, 0, 0,
447 "Memory allocation failed : %s\n", extra);
448 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000449 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000450 NULL, NULL, XML_FROM_RELAXNGP,
451 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
452 NULL, NULL, 0, 0, "Memory allocation failed\n");
453}
454
455/**
456 * xmlRngVErrMemory:
457 * @ctxt: a Relax-NG validation context
458 * @extra: extra informations
459 *
460 * Handle a redefinition of attribute error
461 */
462static void
463xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
464{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000465 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000466 xmlGenericErrorFunc channel = NULL;
467 void *data = NULL;
468
469 if (ctxt != NULL) {
470 channel = ctxt->error;
471 data = ctxt->userData;
472 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000473 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000474 }
475 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000476 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000477 NULL, NULL, XML_FROM_RELAXNGV,
478 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
479 NULL, NULL, 0, 0,
480 "Memory allocation failed : %s\n", extra);
481 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000482 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000483 NULL, NULL, XML_FROM_RELAXNGV,
484 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
485 NULL, NULL, 0, 0, "Memory allocation failed\n");
486}
487
488/**
489 * xmlRngPErr:
490 * @ctxt: a Relax-NG parser context
491 * @node: the node raising the error
492 * @error: the error code
493 * @msg: message
494 * @str1: extra info
495 * @str2: extra info
496 *
497 * Handle a Relax NG Parsing error
498 */
499static void
500xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
501 const char *msg, const xmlChar * str1, const xmlChar * str2)
502{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000503 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000504 xmlGenericErrorFunc channel = NULL;
505 void *data = NULL;
506
507 if (ctxt != NULL) {
508 channel = ctxt->error;
509 data = ctxt->userData;
510 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000511 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000512 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000513 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000514 NULL, node, XML_FROM_RELAXNGP,
515 error, XML_ERR_ERROR, NULL, 0,
516 (const char *) str1, (const char *) str2, NULL, 0, 0,
517 msg, str1, str2);
518}
519
520/**
521 * xmlRngVErr:
522 * @ctxt: a Relax-NG validation context
523 * @node: the node raising the error
524 * @error: the error code
525 * @msg: message
526 * @str1: extra info
527 * @str2: extra info
528 *
529 * Handle a Relax NG Validation error
530 */
531static void
532xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
533 const char *msg, const xmlChar * str1, const xmlChar * str2)
534{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000535 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000536 xmlGenericErrorFunc channel = NULL;
537 void *data = NULL;
538
539 if (ctxt != NULL) {
540 channel = ctxt->error;
541 data = ctxt->userData;
542 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000543 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000544 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000545 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000546 NULL, node, XML_FROM_RELAXNGV,
547 error, XML_ERR_ERROR, NULL, 0,
548 (const char *) str1, (const char *) str2, NULL, 0, 0,
549 msg, str1, str2);
550}
551
552/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000553 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000554 * Preliminary type checking interfaces *
555 * *
556 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000557
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000558/**
559 * xmlRelaxNGTypeHave:
560 * @data: data needed for the library
561 * @type: the type name
562 * @value: the value to check
563 *
564 * Function provided by a type library to check if a type is exported
565 *
566 * Returns 1 if yes, 0 if no and -1 in case of error.
567 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000568typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000569
570/**
571 * xmlRelaxNGTypeCheck:
572 * @data: data needed for the library
573 * @type: the type name
574 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000575 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000576 *
577 * Function provided by a type library to check if a value match a type
578 *
579 * Returns 1 if yes, 0 if no and -1 in case of error.
580 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000581typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
582 const xmlChar * value, void **result,
583 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000584
585/**
586 * xmlRelaxNGFacetCheck:
587 * @data: data needed for the library
588 * @type: the type name
589 * @facet: the facet name
590 * @val: the facet value
591 * @strval: the string value
592 * @value: the value to check
593 *
594 * Function provided by a type library to check a value facet
595 *
596 * Returns 1 if yes, 0 if no and -1 in case of error.
597 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000598typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
599 const xmlChar * facet,
600 const xmlChar * val,
601 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000602
603/**
604 * xmlRelaxNGTypeFree:
605 * @data: data needed for the library
606 * @result: the value to free
607 *
608 * Function provided by a type library to free a returned result
609 */
610typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000611
612/**
613 * xmlRelaxNGTypeCompare:
614 * @data: data needed for the library
615 * @type: the type name
616 * @value1: the first value
617 * @value2: the second value
618 *
619 * Function provided by a type library to compare two values accordingly
620 * to a type.
621 *
622 * Returns 1 if yes, 0 if no and -1 in case of error.
623 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000624typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
625 const xmlChar * value1,
626 xmlNodePtr ctxt1,
627 void *comp1,
628 const xmlChar * value2,
629 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000630typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
631typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
632struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000633 const xmlChar *namespace; /* the datatypeLibrary value */
634 void *data; /* data needed for the library */
635 xmlRelaxNGTypeHave have; /* the export function */
636 xmlRelaxNGTypeCheck check; /* the checking function */
637 xmlRelaxNGTypeCompare comp; /* the compare function */
638 xmlRelaxNGFacetCheck facet; /* the facet check function */
639 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000640};
641
642/************************************************************************
643 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000644 * Allocation functions *
645 * *
646 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000647static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
648static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000649static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000650static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000651static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
652 ATTRIBUTE_UNUSED,
653 xmlRelaxNGValidStatePtr state1,
654 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000655static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000656 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000657
658/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000659 * xmlRelaxNGFreeDocument:
660 * @docu: a document structure
661 *
662 * Deallocate a RelaxNG document structure.
663 */
664static void
665xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
666{
667 if (docu == NULL)
668 return;
669
670 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000671 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000672 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000673 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000674 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000675 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000676 xmlFree(docu);
677}
678
679/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000680 * xmlRelaxNGFreeDocumentList:
681 * @docu: a list of document structure
682 *
683 * Deallocate a RelaxNG document structures.
684 */
685static void
686xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
687{
688 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000689
Daniel Veillardc482e262003-02-26 14:48:48 +0000690 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000691 next = docu->next;
692 xmlRelaxNGFreeDocument(docu);
693 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000694 }
695}
696
697/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000698 * xmlRelaxNGFreeInclude:
699 * @incl: a include structure
700 *
701 * Deallocate a RelaxNG include structure.
702 */
703static void
704xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
705{
706 if (incl == NULL)
707 return;
708
709 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000710 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000711 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000712 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000713 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000714 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000715 xmlFree(incl);
716}
717
718/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000719 * xmlRelaxNGFreeIncludeList:
720 * @incl: a include structure list
721 *
722 * Deallocate a RelaxNG include structure.
723 */
724static void
725xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
726{
727 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000728
Daniel Veillardc482e262003-02-26 14:48:48 +0000729 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000730 next = incl->next;
731 xmlRelaxNGFreeInclude(incl);
732 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000733 }
734}
735
736/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000737 * xmlRelaxNGNewRelaxNG:
738 * @ctxt: a Relax-NG validation context (optional)
739 *
740 * Allocate a new RelaxNG structure.
741 *
742 * Returns the newly allocated structure or NULL in case or error
743 */
744static xmlRelaxNGPtr
745xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
746{
747 xmlRelaxNGPtr ret;
748
749 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
750 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000751 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000752 return (NULL);
753 }
754 memset(ret, 0, sizeof(xmlRelaxNG));
755
756 return (ret);
757}
758
759/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000760 * xmlRelaxNGFreeInnerSchema:
761 * @schema: a schema structure
762 *
763 * Deallocate a RelaxNG schema structure.
764 */
765static void
766xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
767{
768 if (schema == NULL)
769 return;
770
771 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000772 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000773 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000774 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000775
Daniel Veillard4c004142003-10-07 11:33:24 +0000776 for (i = 0; i < schema->defNr; i++)
777 xmlRelaxNGFreeDefine(schema->defTab[i]);
778 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000779 }
780
781 xmlFree(schema);
782}
783
784/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000785 * xmlRelaxNGFree:
786 * @schema: a schema structure
787 *
788 * Deallocate a RelaxNG structure.
789 */
790void
791xmlRelaxNGFree(xmlRelaxNGPtr schema)
792{
793 if (schema == NULL)
794 return;
795
Daniel Veillard6eadf632003-01-23 18:29:16 +0000796 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000797 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000798 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000799 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000800 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000801 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000802 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000803 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000804 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000805 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000806
Daniel Veillard4c004142003-10-07 11:33:24 +0000807 for (i = 0; i < schema->defNr; i++)
808 xmlRelaxNGFreeDefine(schema->defTab[i]);
809 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000810 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000811
812 xmlFree(schema);
813}
814
815/**
816 * xmlRelaxNGNewGrammar:
817 * @ctxt: a Relax-NG validation context (optional)
818 *
819 * Allocate a new RelaxNG grammar.
820 *
821 * Returns the newly allocated structure or NULL in case or error
822 */
823static xmlRelaxNGGrammarPtr
824xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
825{
826 xmlRelaxNGGrammarPtr ret;
827
828 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
829 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000830 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000831 return (NULL);
832 }
833 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
834
835 return (ret);
836}
837
838/**
839 * xmlRelaxNGFreeGrammar:
840 * @grammar: a grammar structure
841 *
842 * Deallocate a RelaxNG grammar structure.
843 */
844static void
845xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
846{
847 if (grammar == NULL)
848 return;
849
Daniel Veillardc482e262003-02-26 14:48:48 +0000850 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000851 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000852 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000853 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000854 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000855 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000856 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000857 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000858 }
859 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000860 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000861 }
862
863 xmlFree(grammar);
864}
865
866/**
867 * xmlRelaxNGNewDefine:
868 * @ctxt: a Relax-NG validation context
869 * @node: the node in the input document.
870 *
871 * Allocate a new RelaxNG define.
872 *
873 * Returns the newly allocated structure or NULL in case or error
874 */
875static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000876xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000877{
878 xmlRelaxNGDefinePtr ret;
879
Daniel Veillard419a7682003-02-03 23:22:49 +0000880 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000881 ctxt->defMax = 16;
882 ctxt->defNr = 0;
883 ctxt->defTab = (xmlRelaxNGDefinePtr *)
884 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
885 if (ctxt->defTab == NULL) {
886 xmlRngPErrMemory(ctxt, "allocating define\n");
887 return (NULL);
888 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000889 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000890 xmlRelaxNGDefinePtr *tmp;
891
892 ctxt->defMax *= 2;
893 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
894 ctxt->defMax *
895 sizeof
896 (xmlRelaxNGDefinePtr));
897 if (tmp == NULL) {
898 xmlRngPErrMemory(ctxt, "allocating define\n");
899 return (NULL);
900 }
901 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000902 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000903 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
904 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000905 xmlRngPErrMemory(ctxt, "allocating define\n");
906 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000907 }
908 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000909 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000910 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000911 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000912 return (ret);
913}
914
915/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000916 * xmlRelaxNGFreePartition:
917 * @partitions: a partition set structure
918 *
919 * Deallocate RelaxNG partition set structures.
920 */
921static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000922xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
923{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000924 xmlRelaxNGInterleaveGroupPtr group;
925 int j;
926
927 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000928 if (partitions->groups != NULL) {
929 for (j = 0; j < partitions->nbgroups; j++) {
930 group = partitions->groups[j];
931 if (group != NULL) {
932 if (group->defs != NULL)
933 xmlFree(group->defs);
934 if (group->attrs != NULL)
935 xmlFree(group->attrs);
936 xmlFree(group);
937 }
938 }
939 xmlFree(partitions->groups);
940 }
941 if (partitions->triage != NULL) {
942 xmlHashFree(partitions->triage, NULL);
943 }
944 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000945 }
946}
Daniel Veillard4c004142003-10-07 11:33:24 +0000947
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000948/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000949 * xmlRelaxNGFreeDefine:
950 * @define: a define structure
951 *
952 * Deallocate a RelaxNG define structure.
953 */
954static void
955xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
956{
957 if (define == NULL)
958 return;
959
Daniel Veillard4c004142003-10-07 11:33:24 +0000960 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
961 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000962
Daniel Veillard4c004142003-10-07 11:33:24 +0000963 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
964 if ((lib != NULL) && (lib->freef != NULL))
965 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000966 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000967 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
968 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
969 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
970 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000971 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000972 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000973 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000974 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000975 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000976 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000977 if (define->contModel != NULL)
978 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000979 xmlFree(define);
980}
981
982/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000983 * xmlRelaxNGNewStates:
984 * @ctxt: a Relax-NG validation context
985 * @size: the default size for the container
986 *
987 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000988 *
989 * Returns the newly allocated structure or NULL in case or error
990 */
991static xmlRelaxNGStatesPtr
992xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
993{
994 xmlRelaxNGStatesPtr ret;
995
Daniel Veillard798024a2003-03-19 10:36:09 +0000996 if ((ctxt != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +0000997 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
998 ctxt->freeStatesNr--;
999 ret = ctxt->freeStates[ctxt->freeStatesNr];
1000 ret->nbState = 0;
1001 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +00001002 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001003 if (size < 16)
1004 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001005
1006 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +00001007 (size -
1008 1) *
1009 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001010 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001011 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001012 return (NULL);
1013 }
1014 ret->nbState = 0;
1015 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001016 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1017 sizeof
1018 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001019 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001020 xmlRngVErrMemory(ctxt, "allocating states\n");
1021 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001022 return (NULL);
1023 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001024 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001025}
1026
1027/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001028 * xmlRelaxNGAddStateUniq:
1029 * @ctxt: a Relax-NG validation context
1030 * @states: the states container
1031 * @state: the validation state
1032 *
1033 * Add a RelaxNG validation state to the container without checking
1034 * for unicity.
1035 *
1036 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1037 */
1038static int
1039xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001040 xmlRelaxNGStatesPtr states,
1041 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001042{
1043 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001044 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001045 }
1046 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001047 xmlRelaxNGValidStatePtr *tmp;
1048 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001049
Daniel Veillard4c004142003-10-07 11:33:24 +00001050 size = states->maxState * 2;
1051 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1052 (size) *
1053 sizeof
1054 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001055 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001056 xmlRngVErrMemory(ctxt, "adding states\n");
1057 return (-1);
1058 }
1059 states->tabState = tmp;
1060 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001061 }
1062 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001063 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001064}
1065
1066/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001067 * xmlRelaxNGAddState:
1068 * @ctxt: a Relax-NG validation context
1069 * @states: the states container
1070 * @state: the validation state
1071 *
1072 * Add a RelaxNG validation state to the container
1073 *
1074 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1075 */
1076static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001077xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1078 xmlRelaxNGStatesPtr states,
1079 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001080{
1081 int i;
1082
1083 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001084 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001085 }
1086 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001087 xmlRelaxNGValidStatePtr *tmp;
1088 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001089
Daniel Veillard4c004142003-10-07 11:33:24 +00001090 size = states->maxState * 2;
1091 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1092 (size) *
1093 sizeof
1094 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001095 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001096 xmlRngVErrMemory(ctxt, "adding states\n");
1097 return (-1);
1098 }
1099 states->tabState = tmp;
1100 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001101 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001102 for (i = 0; i < states->nbState; i++) {
1103 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1104 xmlRelaxNGFreeValidState(ctxt, state);
1105 return (0);
1106 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001107 }
1108 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001109 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001110}
1111
1112/**
1113 * xmlRelaxNGFreeStates:
1114 * @ctxt: a Relax-NG validation context
1115 * @states: teh container
1116 *
1117 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001118 */
1119static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001120xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001121 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001122{
Daniel Veillard798024a2003-03-19 10:36:09 +00001123 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001124 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001125 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001126 ctxt->freeStatesMax = 40;
1127 ctxt->freeStatesNr = 0;
1128 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1129 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1130 if (ctxt->freeStates == NULL) {
1131 xmlRngVErrMemory(ctxt, "storing states\n");
1132 }
1133 } else if ((ctxt != NULL)
1134 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1135 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001136
Daniel Veillard4c004142003-10-07 11:33:24 +00001137 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1138 2 * ctxt->freeStatesMax *
1139 sizeof
1140 (xmlRelaxNGStatesPtr));
1141 if (tmp == NULL) {
1142 xmlRngVErrMemory(ctxt, "storing states\n");
1143 xmlFree(states->tabState);
1144 xmlFree(states);
1145 return;
1146 }
1147 ctxt->freeStates = tmp;
1148 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001149 }
1150 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001151 xmlFree(states->tabState);
1152 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001153 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001154 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001155 }
1156}
1157
1158/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001159 * xmlRelaxNGNewValidState:
1160 * @ctxt: a Relax-NG validation context
1161 * @node: the current node or NULL for the document
1162 *
1163 * Allocate a new RelaxNG validation state
1164 *
1165 * Returns the newly allocated structure or NULL in case or error
1166 */
1167static xmlRelaxNGValidStatePtr
1168xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1169{
1170 xmlRelaxNGValidStatePtr ret;
1171 xmlAttrPtr attr;
1172 xmlAttrPtr attrs[MAX_ATTR];
1173 int nbAttrs = 0;
1174 xmlNodePtr root = NULL;
1175
1176 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001177 root = xmlDocGetRootElement(ctxt->doc);
1178 if (root == NULL)
1179 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001180 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001181 attr = node->properties;
1182 while (attr != NULL) {
1183 if (nbAttrs < MAX_ATTR)
1184 attrs[nbAttrs++] = attr;
1185 else
1186 nbAttrs++;
1187 attr = attr->next;
1188 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001189 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001190 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1191 ctxt->freeState->nbState--;
1192 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001193 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001194 ret =
1195 (xmlRelaxNGValidStatePtr)
1196 xmlMalloc(sizeof(xmlRelaxNGValidState));
1197 if (ret == NULL) {
1198 xmlRngVErrMemory(ctxt, "allocating states\n");
1199 return (NULL);
1200 }
1201 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001202 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001203 ret->value = NULL;
1204 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001205 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001206 ret->node = (xmlNodePtr) ctxt->doc;
1207 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001208 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001209 ret->node = node;
1210 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001211 }
1212 ret->nbAttrs = 0;
1213 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001214 if (ret->attrs == NULL) {
1215 if (nbAttrs < 4)
1216 ret->maxAttrs = 4;
1217 else
1218 ret->maxAttrs = nbAttrs;
1219 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1220 sizeof(xmlAttrPtr));
1221 if (ret->attrs == NULL) {
1222 xmlRngVErrMemory(ctxt, "allocating states\n");
1223 return (ret);
1224 }
1225 } else if (ret->maxAttrs < nbAttrs) {
1226 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001227
Daniel Veillard4c004142003-10-07 11:33:24 +00001228 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1229 sizeof(xmlAttrPtr));
1230 if (tmp == NULL) {
1231 xmlRngVErrMemory(ctxt, "allocating states\n");
1232 return (ret);
1233 }
1234 ret->attrs = tmp;
1235 ret->maxAttrs = nbAttrs;
1236 }
1237 ret->nbAttrs = nbAttrs;
1238 if (nbAttrs < MAX_ATTR) {
1239 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1240 } else {
1241 attr = node->properties;
1242 nbAttrs = 0;
1243 while (attr != NULL) {
1244 ret->attrs[nbAttrs++] = attr;
1245 attr = attr->next;
1246 }
1247 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001248 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001249 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001250 return (ret);
1251}
1252
1253/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001254 * xmlRelaxNGCopyValidState:
1255 * @ctxt: a Relax-NG validation context
1256 * @state: a validation state
1257 *
1258 * Copy the validation state
1259 *
1260 * Returns the newly allocated structure or NULL in case or error
1261 */
1262static xmlRelaxNGValidStatePtr
1263xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001264 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001265{
1266 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001267 unsigned int maxAttrs;
1268 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001269
1270 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001271 return (NULL);
1272 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1273 ctxt->freeState->nbState--;
1274 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001275 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001276 ret =
1277 (xmlRelaxNGValidStatePtr)
1278 xmlMalloc(sizeof(xmlRelaxNGValidState));
1279 if (ret == NULL) {
1280 xmlRngVErrMemory(ctxt, "allocating states\n");
1281 return (NULL);
1282 }
1283 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001284 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001285 attrs = ret->attrs;
1286 maxAttrs = ret->maxAttrs;
1287 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1288 ret->attrs = attrs;
1289 ret->maxAttrs = maxAttrs;
1290 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001291 if (ret->attrs == NULL) {
1292 ret->maxAttrs = state->maxAttrs;
1293 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1294 sizeof(xmlAttrPtr));
1295 if (ret->attrs == NULL) {
1296 xmlRngVErrMemory(ctxt, "allocating states\n");
1297 ret->nbAttrs = 0;
1298 return (ret);
1299 }
1300 } else if (ret->maxAttrs < state->nbAttrs) {
1301 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001302
Daniel Veillard4c004142003-10-07 11:33:24 +00001303 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1304 sizeof(xmlAttrPtr));
1305 if (tmp == NULL) {
1306 xmlRngVErrMemory(ctxt, "allocating states\n");
1307 ret->nbAttrs = 0;
1308 return (ret);
1309 }
1310 ret->maxAttrs = state->maxAttrs;
1311 ret->attrs = tmp;
1312 }
1313 memcpy(ret->attrs, state->attrs,
1314 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001315 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001316 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001317}
1318
1319/**
1320 * xmlRelaxNGEqualValidState:
1321 * @ctxt: a Relax-NG validation context
1322 * @state1: a validation state
1323 * @state2: a validation state
1324 *
1325 * Compare the validation states for equality
1326 *
1327 * Returns 1 if equald, 0 otherwise
1328 */
1329static int
1330xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001331 xmlRelaxNGValidStatePtr state1,
1332 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001333{
1334 int i;
1335
1336 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001337 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001338 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001339 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001340 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001341 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001342 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001343 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001344 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001345 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001346 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001347 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001348 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001349 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001350 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001351 (!xmlStrEqual(state1->value, state2->value)))
1352 return (0);
1353 for (i = 0; i < state1->nbAttrs; i++) {
1354 if (state1->attrs[i] != state2->attrs[i])
1355 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001356 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001357 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001358}
1359
1360/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001361 * xmlRelaxNGFreeValidState:
1362 * @state: a validation state structure
1363 *
1364 * Deallocate a RelaxNG validation state structure.
1365 */
1366static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001367xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001368 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001369{
1370 if (state == NULL)
1371 return;
1372
Daniel Veillard798024a2003-03-19 10:36:09 +00001373 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001374 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001375 }
1376 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001377 if (state->attrs != NULL)
1378 xmlFree(state->attrs);
1379 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001380 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001381 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001382 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001383}
1384
1385/************************************************************************
1386 * *
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001387 * Semi internal functions *
1388 * *
1389 ************************************************************************/
1390
1391/**
1392 * xmlRelaxParserSetFlag:
1393 * @ctxt: a RelaxNG parser context
1394 * @flags: a set of flags values
1395 *
1396 * Semi private function used to pass informations to a parser context
1397 * which are a combination of xmlRelaxNGParserFlag .
1398 *
1399 * Returns 0 if success and -1 in case of error
1400 */
1401int
1402xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1403{
1404 if (ctxt == NULL) return(-1);
1405 if (flags & XML_RELAXNGP_FREE_DOC) {
1406 ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1407 flags -= XML_RELAXNGP_FREE_DOC;
1408 }
1409 if (flags & XML_RELAXNGP_CRNG) {
1410 ctxt->crng |= XML_RELAXNGP_CRNG;
1411 flags -= XML_RELAXNGP_CRNG;
1412 }
1413 if (flags != 0) return(-1);
1414 return(0);
1415}
1416
1417/************************************************************************
1418 * *
1419 * Document functions *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001420 * *
1421 ************************************************************************/
1422static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001423 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001424
1425/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001426 * xmlRelaxNGIncludePush:
1427 * @ctxt: the parser context
1428 * @value: the element doc
1429 *
1430 * Pushes a new include on top of the include stack
1431 *
1432 * Returns 0 in case of error, the index in the stack otherwise
1433 */
1434static int
1435xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001436 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001437{
1438 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001439 ctxt->incMax = 4;
1440 ctxt->incNr = 0;
1441 ctxt->incTab =
1442 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1443 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001444 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001445 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001446 return (0);
1447 }
1448 }
1449 if (ctxt->incNr >= ctxt->incMax) {
1450 ctxt->incMax *= 2;
1451 ctxt->incTab =
1452 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001453 ctxt->incMax *
1454 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001455 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001456 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001457 return (0);
1458 }
1459 }
1460 ctxt->incTab[ctxt->incNr] = value;
1461 ctxt->inc = value;
1462 return (ctxt->incNr++);
1463}
1464
1465/**
1466 * xmlRelaxNGIncludePop:
1467 * @ctxt: the parser context
1468 *
1469 * Pops the top include from the include stack
1470 *
1471 * Returns the include just removed
1472 */
1473static xmlRelaxNGIncludePtr
1474xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1475{
1476 xmlRelaxNGIncludePtr ret;
1477
1478 if (ctxt->incNr <= 0)
1479 return (0);
1480 ctxt->incNr--;
1481 if (ctxt->incNr > 0)
1482 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1483 else
1484 ctxt->inc = NULL;
1485 ret = ctxt->incTab[ctxt->incNr];
1486 ctxt->incTab[ctxt->incNr] = 0;
1487 return (ret);
1488}
1489
1490/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001491 * xmlRelaxNGRemoveRedefine:
1492 * @ctxt: the parser context
1493 * @URL: the normalized URL
1494 * @target: the included target
1495 * @name: the define name to eliminate
1496 *
1497 * Applies the elimination algorithm of 4.7
1498 *
1499 * Returns 0 in case of error, 1 in case of success.
1500 */
1501static int
1502xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001503 const xmlChar * URL ATTRIBUTE_UNUSED,
1504 xmlNodePtr target, const xmlChar * name)
1505{
Daniel Veillard5add8682003-03-10 13:13:58 +00001506 int found = 0;
1507 xmlNodePtr tmp, tmp2;
1508 xmlChar *name2;
1509
1510#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001511 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001512 xmlGenericError(xmlGenericErrorContext,
1513 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001514 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001515 xmlGenericError(xmlGenericErrorContext,
1516 "Elimination of <include> define %s from %s\n",
1517 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001518#endif
1519 tmp = target;
1520 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001521 tmp2 = tmp->next;
1522 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1523 found = 1;
1524 xmlUnlinkNode(tmp);
1525 xmlFreeNode(tmp);
1526 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1527 name2 = xmlGetProp(tmp, BAD_CAST "name");
1528 xmlRelaxNGNormExtSpace(name2);
1529 if (name2 != NULL) {
1530 if (xmlStrEqual(name, name2)) {
1531 found = 1;
1532 xmlUnlinkNode(tmp);
1533 xmlFreeNode(tmp);
1534 }
1535 xmlFree(name2);
1536 }
1537 } else if (IS_RELAXNG(tmp, "include")) {
1538 xmlChar *href = NULL;
Daniel Veillard807daf82004-02-22 22:13:27 +00001539 xmlRelaxNGDocumentPtr inc = tmp->psvi;
Daniel Veillard5add8682003-03-10 13:13:58 +00001540
Daniel Veillard4c004142003-10-07 11:33:24 +00001541 if ((inc != NULL) && (inc->doc != NULL) &&
1542 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001543
Daniel Veillard4c004142003-10-07 11:33:24 +00001544 if (xmlStrEqual
1545 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001546#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001547 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001548#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001549 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1550 inc->doc->children->
1551 children, name) == 1) {
1552 found = 1;
1553 }
1554 if (href != NULL)
1555 xmlFree(href);
1556 }
1557 }
1558 }
1559 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001560 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001561 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001562}
1563
1564/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001565 * xmlRelaxNGLoadInclude:
1566 * @ctxt: the parser context
1567 * @URL: the normalized URL
1568 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001569 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001570 *
1571 * First lookup if the document is already loaded into the parser context,
1572 * check against recursion. If not found the resource is loaded and
1573 * the content is preprocessed before being returned back to the caller.
1574 *
1575 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1576 */
1577static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001578xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1579 xmlNodePtr node, const xmlChar * ns)
1580{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001581 xmlRelaxNGIncludePtr ret = NULL;
1582 xmlDocPtr doc;
1583 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001584 xmlNodePtr root, cur;
1585
1586#ifdef DEBUG_INCLUDE
1587 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001588 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001589#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001590
1591 /*
1592 * check against recursion in the stack
1593 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001594 for (i = 0; i < ctxt->incNr; i++) {
1595 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1596 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1597 "Detected an Include recursion for %s\n", URL,
1598 NULL);
1599 return (NULL);
1600 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001601 }
1602
1603 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001604 * load the document
1605 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001606 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001607 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001608 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1609 "xmlRelaxNG: could not load %s\n", URL, NULL);
1610 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001611 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001612#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001613 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001614#endif
1615
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001616 /*
1617 * Allocate the document structures and register it first.
1618 */
1619 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1620 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001621 xmlRngPErrMemory(ctxt, "allocating include\n");
1622 xmlFreeDoc(doc);
1623 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001624 }
1625 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1626 ret->doc = doc;
1627 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001628 ret->next = ctxt->includes;
1629 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001630
1631 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001632 * transmit the ns if needed
1633 */
1634 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001635 root = xmlDocGetRootElement(doc);
1636 if (root != NULL) {
1637 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1638 xmlSetProp(root, BAD_CAST "ns", ns);
1639 }
1640 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001641 }
1642
1643 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001644 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001645 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001646 xmlRelaxNGIncludePush(ctxt, ret);
1647
1648 /*
1649 * Some preprocessing of the document content, this include recursing
1650 * in the include stack.
1651 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001652#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001653 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001654#endif
1655
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001656 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1657 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001658 ctxt->inc = NULL;
1659 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001660 }
1661
1662 /*
1663 * Pop up the include from the stack
1664 */
1665 xmlRelaxNGIncludePop(ctxt);
1666
Daniel Veillard5add8682003-03-10 13:13:58 +00001667#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001668 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001669#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001670 /*
1671 * Check that the top element is a grammar
1672 */
1673 root = xmlDocGetRootElement(doc);
1674 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001675 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1676 "xmlRelaxNG: included document is empty %s\n", URL,
1677 NULL);
1678 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001679 }
1680 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001681 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1682 "xmlRelaxNG: included document %s root is not a grammar\n",
1683 URL, NULL);
1684 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001685 }
1686
1687 /*
1688 * Elimination of redefined rules in the include.
1689 */
1690 cur = node->children;
1691 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001692 if (IS_RELAXNG(cur, "start")) {
1693 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001694
Daniel Veillard4c004142003-10-07 11:33:24 +00001695 found =
1696 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1697 if (!found) {
1698 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1699 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1700 URL, NULL);
1701 }
1702 } else if (IS_RELAXNG(cur, "define")) {
1703 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001704
Daniel Veillard4c004142003-10-07 11:33:24 +00001705 name = xmlGetProp(cur, BAD_CAST "name");
1706 if (name == NULL) {
1707 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1708 "xmlRelaxNG: include %s has define without name\n",
1709 URL, NULL);
1710 } else {
1711 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001712
Daniel Veillard4c004142003-10-07 11:33:24 +00001713 xmlRelaxNGNormExtSpace(name);
1714 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1715 root->children, name);
1716 if (!found) {
1717 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1718 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1719 URL, name);
1720 }
1721 xmlFree(name);
1722 }
1723 }
1724 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001725 }
1726
1727
Daniel Veillard4c004142003-10-07 11:33:24 +00001728 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001729}
1730
1731/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001732 * xmlRelaxNGValidErrorPush:
1733 * @ctxt: the validation context
1734 * @err: the error code
1735 * @arg1: the first string argument
1736 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001737 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001738 *
1739 * Pushes a new error on top of the error stack
1740 *
1741 * Returns 0 in case of error, the index in the stack otherwise
1742 */
1743static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001744xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1745 xmlRelaxNGValidErr err, const xmlChar * arg1,
1746 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001747{
1748 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001749
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001750#ifdef DEBUG_ERROR
1751 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001752 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001753#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001754 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001755 ctxt->errMax = 8;
1756 ctxt->errNr = 0;
1757 ctxt->errTab =
1758 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1759 sizeof
1760 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001761 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001762 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001763 return (0);
1764 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001765 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001766 }
1767 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001768 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001769 ctxt->errTab =
1770 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001771 ctxt->errMax *
1772 sizeof
1773 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001774 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001775 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001776 return (0);
1777 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001778 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001779 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001780 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001781 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1782 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001783 cur = &ctxt->errTab[ctxt->errNr];
1784 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001785 if (dup) {
1786 cur->arg1 = xmlStrdup(arg1);
1787 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001788 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001789 } else {
1790 cur->arg1 = arg1;
1791 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001792 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001793 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001794 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001795 cur->node = ctxt->state->node;
1796 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001797 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001798 cur->node = NULL;
1799 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001800 }
1801 ctxt->err = cur;
1802 return (ctxt->errNr++);
1803}
1804
1805/**
1806 * xmlRelaxNGValidErrorPop:
1807 * @ctxt: the validation context
1808 *
1809 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001810 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001811static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001812xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1813{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001814 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001815
Daniel Veillard580ced82003-03-21 21:22:48 +00001816 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001817 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001818 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001819 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001820 ctxt->errNr--;
1821 if (ctxt->errNr > 0)
1822 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1823 else
1824 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001825 cur = &ctxt->errTab[ctxt->errNr];
1826 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001827 if (cur->arg1 != NULL)
1828 xmlFree((xmlChar *) cur->arg1);
1829 cur->arg1 = NULL;
1830 if (cur->arg2 != NULL)
1831 xmlFree((xmlChar *) cur->arg2);
1832 cur->arg2 = NULL;
1833 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001834 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001835}
1836
Daniel Veillard42f12e92003-03-07 18:32:59 +00001837/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001838 * xmlRelaxNGDocumentPush:
1839 * @ctxt: the parser context
1840 * @value: the element doc
1841 *
1842 * Pushes a new doc on top of the doc stack
1843 *
1844 * Returns 0 in case of error, the index in the stack otherwise
1845 */
1846static int
1847xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001848 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001849{
1850 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001851 ctxt->docMax = 4;
1852 ctxt->docNr = 0;
1853 ctxt->docTab =
1854 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1855 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001856 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001857 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001858 return (0);
1859 }
1860 }
1861 if (ctxt->docNr >= ctxt->docMax) {
1862 ctxt->docMax *= 2;
1863 ctxt->docTab =
1864 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001865 ctxt->docMax *
1866 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001867 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001868 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001869 return (0);
1870 }
1871 }
1872 ctxt->docTab[ctxt->docNr] = value;
1873 ctxt->doc = value;
1874 return (ctxt->docNr++);
1875}
1876
1877/**
1878 * xmlRelaxNGDocumentPop:
1879 * @ctxt: the parser context
1880 *
1881 * Pops the top doc from the doc stack
1882 *
1883 * Returns the doc just removed
1884 */
1885static xmlRelaxNGDocumentPtr
1886xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1887{
1888 xmlRelaxNGDocumentPtr ret;
1889
1890 if (ctxt->docNr <= 0)
1891 return (0);
1892 ctxt->docNr--;
1893 if (ctxt->docNr > 0)
1894 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1895 else
1896 ctxt->doc = NULL;
1897 ret = ctxt->docTab[ctxt->docNr];
1898 ctxt->docTab[ctxt->docNr] = 0;
1899 return (ret);
1900}
1901
1902/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001903 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001904 * @ctxt: the parser context
1905 * @URL: the normalized URL
1906 * @ns: the inherited ns if any
1907 *
1908 * First lookup if the document is already loaded into the parser context,
1909 * check against recursion. If not found the resource is loaded and
1910 * the content is preprocessed before being returned back to the caller.
1911 *
1912 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1913 */
1914static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001915xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1916 const xmlChar * URL, const xmlChar * ns)
1917{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001918 xmlRelaxNGDocumentPtr ret = NULL;
1919 xmlDocPtr doc;
1920 xmlNodePtr root;
1921 int i;
1922
1923 /*
1924 * check against recursion in the stack
1925 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001926 for (i = 0; i < ctxt->docNr; i++) {
1927 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1928 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1929 "Detected an externalRef recursion for %s\n", URL,
1930 NULL);
1931 return (NULL);
1932 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001933 }
1934
1935 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001936 * load the document
1937 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001938 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001939 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001940 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1941 "xmlRelaxNG: could not load %s\n", URL, NULL);
1942 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001943 }
1944
1945 /*
1946 * Allocate the document structures and register it first.
1947 */
1948 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1949 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001950 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1951 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1952 xmlFreeDoc(doc);
1953 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001954 }
1955 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1956 ret->doc = doc;
1957 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001958 ret->next = ctxt->documents;
1959 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001960
1961 /*
1962 * transmit the ns if needed
1963 */
1964 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001965 root = xmlDocGetRootElement(doc);
1966 if (root != NULL) {
1967 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1968 xmlSetProp(root, BAD_CAST "ns", ns);
1969 }
1970 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001971 }
1972
1973 /*
1974 * push it on the stack and register it in the hash table
1975 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001976 xmlRelaxNGDocumentPush(ctxt, ret);
1977
1978 /*
1979 * Some preprocessing of the document content
1980 */
1981 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1982 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001983 ctxt->doc = NULL;
1984 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001985 }
1986
1987 xmlRelaxNGDocumentPop(ctxt);
1988
Daniel Veillard4c004142003-10-07 11:33:24 +00001989 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001990}
1991
1992/************************************************************************
1993 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001994 * Error functions *
1995 * *
1996 ************************************************************************/
1997
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001998#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1999#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2000#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2001#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2002#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002003
Daniel Veillard231d7912003-02-09 14:22:17 +00002004static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00002005xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2006{
Daniel Veillard231d7912003-02-09 14:22:17 +00002007 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002008 return ("none");
2009 switch (def->type) {
2010 case XML_RELAXNG_EMPTY:
2011 return ("empty");
2012 case XML_RELAXNG_NOT_ALLOWED:
2013 return ("notAllowed");
2014 case XML_RELAXNG_EXCEPT:
2015 return ("except");
2016 case XML_RELAXNG_TEXT:
2017 return ("text");
2018 case XML_RELAXNG_ELEMENT:
2019 return ("element");
2020 case XML_RELAXNG_DATATYPE:
2021 return ("datatype");
2022 case XML_RELAXNG_VALUE:
2023 return ("value");
2024 case XML_RELAXNG_LIST:
2025 return ("list");
2026 case XML_RELAXNG_ATTRIBUTE:
2027 return ("attribute");
2028 case XML_RELAXNG_DEF:
2029 return ("def");
2030 case XML_RELAXNG_REF:
2031 return ("ref");
2032 case XML_RELAXNG_EXTERNALREF:
2033 return ("externalRef");
2034 case XML_RELAXNG_PARENTREF:
2035 return ("parentRef");
2036 case XML_RELAXNG_OPTIONAL:
2037 return ("optional");
2038 case XML_RELAXNG_ZEROORMORE:
2039 return ("zeroOrMore");
2040 case XML_RELAXNG_ONEORMORE:
2041 return ("oneOrMore");
2042 case XML_RELAXNG_CHOICE:
2043 return ("choice");
2044 case XML_RELAXNG_GROUP:
2045 return ("group");
2046 case XML_RELAXNG_INTERLEAVE:
2047 return ("interleave");
2048 case XML_RELAXNG_START:
2049 return ("start");
2050 case XML_RELAXNG_NOOP:
2051 return ("noop");
2052 case XML_RELAXNG_PARAM:
2053 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002054 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002055 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002056}
Daniel Veillardd2298792003-02-14 16:54:11 +00002057
Daniel Veillard6eadf632003-01-23 18:29:16 +00002058/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002059 * xmlRelaxNGGetErrorString:
2060 * @err: the error code
2061 * @arg1: the first string argument
2062 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002063 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002064 * computes a formatted error string for the given error code and args
2065 *
2066 * Returns the error string, it must be deallocated by the caller
2067 */
2068static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002069xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2070 const xmlChar * arg2)
2071{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002072 char msg[1000];
2073
2074 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002075 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002076 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002077 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002078
2079 msg[0] = 0;
2080 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002081 case XML_RELAXNG_OK:
2082 return (NULL);
2083 case XML_RELAXNG_ERR_MEMORY:
2084 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002085 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002086 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2087 break;
2088 case XML_RELAXNG_ERR_TYPEVAL:
2089 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2090 arg2);
2091 break;
2092 case XML_RELAXNG_ERR_DUPID:
2093 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2094 break;
2095 case XML_RELAXNG_ERR_TYPECMP:
2096 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2097 break;
2098 case XML_RELAXNG_ERR_NOSTATE:
2099 return (xmlCharStrdup("Internal error: no state\n"));
2100 case XML_RELAXNG_ERR_NODEFINE:
2101 return (xmlCharStrdup("Internal error: no define\n"));
2102 case XML_RELAXNG_ERR_INTERNAL:
2103 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2104 break;
2105 case XML_RELAXNG_ERR_LISTEXTRA:
2106 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2107 break;
2108 case XML_RELAXNG_ERR_INTERNODATA:
2109 return (xmlCharStrdup
2110 ("Internal: interleave block has no data\n"));
2111 case XML_RELAXNG_ERR_INTERSEQ:
2112 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2113 case XML_RELAXNG_ERR_INTEREXTRA:
2114 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2115 break;
2116 case XML_RELAXNG_ERR_ELEMNAME:
2117 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2118 arg2);
2119 break;
2120 case XML_RELAXNG_ERR_ELEMNONS:
2121 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2122 arg1);
2123 break;
2124 case XML_RELAXNG_ERR_ELEMWRONGNS:
2125 snprintf(msg, 1000,
2126 "Element %s has wrong namespace: expecting %s\n", arg1,
2127 arg2);
2128 break;
2129 case XML_RELAXNG_ERR_ELEMWRONG:
2130 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2131 break;
2132 case XML_RELAXNG_ERR_TEXTWRONG:
2133 snprintf(msg, 1000,
2134 "Did not expect text in element %s content\n", arg1);
2135 break;
2136 case XML_RELAXNG_ERR_ELEMEXTRANS:
2137 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2138 arg1);
2139 break;
2140 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2141 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2142 break;
2143 case XML_RELAXNG_ERR_NOELEM:
2144 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2145 arg1);
2146 break;
2147 case XML_RELAXNG_ERR_NOTELEM:
2148 return (xmlCharStrdup("Expecting an element got text\n"));
2149 case XML_RELAXNG_ERR_ATTRVALID:
2150 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2151 arg1);
2152 break;
2153 case XML_RELAXNG_ERR_CONTENTVALID:
2154 snprintf(msg, 1000, "Element %s failed to validate content\n",
2155 arg1);
2156 break;
2157 case XML_RELAXNG_ERR_EXTRACONTENT:
2158 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2159 arg1, arg2);
2160 break;
2161 case XML_RELAXNG_ERR_INVALIDATTR:
2162 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2163 arg1, arg2);
2164 break;
2165 case XML_RELAXNG_ERR_LACKDATA:
2166 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2167 arg1);
2168 break;
2169 case XML_RELAXNG_ERR_DATAELEM:
2170 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2171 arg1);
2172 break;
2173 case XML_RELAXNG_ERR_VALELEM:
2174 snprintf(msg, 1000, "Value element %s has child elements\n",
2175 arg1);
2176 break;
2177 case XML_RELAXNG_ERR_LISTELEM:
2178 snprintf(msg, 1000, "List element %s has child elements\n",
2179 arg1);
2180 break;
2181 case XML_RELAXNG_ERR_DATATYPE:
2182 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2183 break;
2184 case XML_RELAXNG_ERR_VALUE:
2185 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2186 break;
2187 case XML_RELAXNG_ERR_LIST:
2188 return (xmlCharStrdup("Error validating list\n"));
2189 case XML_RELAXNG_ERR_NOGRAMMAR:
2190 return (xmlCharStrdup("No top grammar defined\n"));
2191 case XML_RELAXNG_ERR_EXTRADATA:
2192 return (xmlCharStrdup("Extra data in the document\n"));
2193 default:
2194 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002195 }
2196 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002197 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002198 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002199 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002200 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002201}
2202
2203/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002204 * xmlRelaxNGShowValidError:
2205 * @ctxt: the validation context
2206 * @err: the error number
2207 * @node: the node
2208 * @child: the node child generating the problem.
2209 * @arg1: the first argument
2210 * @arg2: the second argument
2211 *
2212 * Show a validation error.
2213 */
2214static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002215xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2216 xmlRelaxNGValidErr err, xmlNodePtr node,
2217 xmlNodePtr child, const xmlChar * arg1,
2218 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002219{
2220 xmlChar *msg;
2221
2222 if (ctxt->error == NULL)
2223 return;
2224
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002225#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002226 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002227#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002228 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2229 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002230 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002231
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002232 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002233 ctxt->errNo = err;
2234 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2235 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002236 xmlFree(msg);
2237}
2238
2239/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002240 * xmlRelaxNGPopErrors:
2241 * @ctxt: the validation context
2242 * @level: the error level in the stack
2243 *
2244 * pop and discard all errors until the given level is reached
2245 */
2246static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002247xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2248{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002249 int i;
2250 xmlRelaxNGValidErrorPtr err;
2251
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002252#ifdef DEBUG_ERROR
2253 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002254 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002255#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002256 for (i = level; i < ctxt->errNr; i++) {
2257 err = &ctxt->errTab[i];
2258 if (err->flags & ERROR_IS_DUP) {
2259 if (err->arg1 != NULL)
2260 xmlFree((xmlChar *) err->arg1);
2261 err->arg1 = NULL;
2262 if (err->arg2 != NULL)
2263 xmlFree((xmlChar *) err->arg2);
2264 err->arg2 = NULL;
2265 err->flags = 0;
2266 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002267 }
2268 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002269 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002270 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002271}
Daniel Veillard4c004142003-10-07 11:33:24 +00002272
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002273/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002274 * xmlRelaxNGDumpValidError:
2275 * @ctxt: the validation context
2276 *
2277 * Show all validation error over a given index.
2278 */
2279static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002280xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2281{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002282 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002283 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002284
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002285#ifdef DEBUG_ERROR
2286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002287 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002288#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002289 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2290 err = &ctxt->errTab[i];
2291 if (k < MAX_ERROR) {
2292 for (j = 0; j < i; j++) {
2293 dup = &ctxt->errTab[j];
2294 if ((err->err == dup->err) && (err->node == dup->node) &&
2295 (xmlStrEqual(err->arg1, dup->arg1)) &&
2296 (xmlStrEqual(err->arg2, dup->arg2))) {
2297 goto skip;
2298 }
2299 }
2300 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2301 err->arg1, err->arg2);
2302 k++;
2303 }
2304 skip:
2305 if (err->flags & ERROR_IS_DUP) {
2306 if (err->arg1 != NULL)
2307 xmlFree((xmlChar *) err->arg1);
2308 err->arg1 = NULL;
2309 if (err->arg2 != NULL)
2310 xmlFree((xmlChar *) err->arg2);
2311 err->arg2 = NULL;
2312 err->flags = 0;
2313 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002314 }
2315 ctxt->errNr = 0;
2316}
Daniel Veillard4c004142003-10-07 11:33:24 +00002317
Daniel Veillard42f12e92003-03-07 18:32:59 +00002318/**
2319 * xmlRelaxNGAddValidError:
2320 * @ctxt: the validation context
2321 * @err: the error number
2322 * @arg1: the first argument
2323 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002324 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002325 *
2326 * Register a validation error, either generating it if it's sure
2327 * or stacking it for later handling if unsure.
2328 */
2329static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002330xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2331 xmlRelaxNGValidErr err, const xmlChar * arg1,
2332 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002333{
2334 if ((ctxt == NULL) || (ctxt->error == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002335 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002336
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002337#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002338 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002339#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002340 /*
2341 * generate the error directly
2342 */
William M. Brack60929622004-03-27 17:54:18 +00002343 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2344 (ctxt->flags & FLAGS_NEGATIVE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002345 xmlNodePtr node, seq;
2346
2347 /*
2348 * Flush first any stacked error which might be the
2349 * real cause of the problem.
2350 */
2351 if (ctxt->errNr != 0)
2352 xmlRelaxNGDumpValidError(ctxt);
2353 if (ctxt->state != NULL) {
2354 node = ctxt->state->node;
2355 seq = ctxt->state->seq;
2356 } else {
2357 node = seq = NULL;
2358 }
2359 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002360 }
2361 /*
2362 * Stack the error for later processing if needed
2363 */
2364 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002365 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002366 }
2367}
2368
Daniel Veillard6eadf632003-01-23 18:29:16 +00002369
2370/************************************************************************
2371 * *
2372 * Type library hooks *
2373 * *
2374 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002375static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002376 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002377
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002378/**
2379 * xmlRelaxNGSchemaTypeHave:
2380 * @data: data needed for the library
2381 * @type: the type name
2382 *
2383 * Check if the given type is provided by
2384 * the W3C XMLSchema Datatype library.
2385 *
2386 * Returns 1 if yes, 0 if no and -1 in case of error.
2387 */
2388static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002389xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2390{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002391 xmlSchemaTypePtr typ;
2392
2393 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002394 return (-1);
2395 typ = xmlSchemaGetPredefinedType(type,
2396 BAD_CAST
2397 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002398 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002399 return (0);
2400 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002401}
2402
2403/**
2404 * xmlRelaxNGSchemaTypeCheck:
2405 * @data: data needed for the library
2406 * @type: the type name
2407 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002408 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002409 *
2410 * Check if the given type and value are validated by
2411 * the W3C XMLSchema Datatype library.
2412 *
2413 * Returns 1 if yes, 0 if no and -1 in case of error.
2414 */
2415static int
2416xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002417 const xmlChar * type,
2418 const xmlChar * value,
2419 void **result, xmlNodePtr node)
2420{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002421 xmlSchemaTypePtr typ;
2422 int ret;
2423
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002424 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002425 return (-1);
2426 typ = xmlSchemaGetPredefinedType(type,
2427 BAD_CAST
2428 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002429 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002430 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002431 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002432 (xmlSchemaValPtr *) result, node);
2433 if (ret == 2) /* special ID error code */
2434 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002435 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002436 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002437 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002438 return (0);
2439 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002440}
2441
2442/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002443 * xmlRelaxNGSchemaFacetCheck:
2444 * @data: data needed for the library
2445 * @type: the type name
2446 * @facet: the facet name
2447 * @val: the facet value
2448 * @strval: the string value
2449 * @value: the value to check
2450 *
2451 * Function provided by a type library to check a value facet
2452 *
2453 * Returns 1 if yes, 0 if no and -1 in case of error.
2454 */
2455static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002456xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2457 const xmlChar * type, const xmlChar * facetname,
2458 const xmlChar * val, const xmlChar * strval,
2459 void *value)
2460{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002461 xmlSchemaFacetPtr facet;
2462 xmlSchemaTypePtr typ;
2463 int ret;
2464
2465 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002466 return (-1);
2467 typ = xmlSchemaGetPredefinedType(type,
2468 BAD_CAST
2469 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002470 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002471 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002472
2473 facet = xmlSchemaNewFacet();
2474 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002475 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002476
Daniel Veillard4c004142003-10-07 11:33:24 +00002477 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002478 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002479 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002480 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002481 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002482 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002483 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002484 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002485 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002486 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002487 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002488 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002489 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002490 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002491 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002492 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002493 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002494 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002495 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002496 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002497 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002498 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2499 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2500 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2501 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002502 xmlSchemaFreeFacet(facet);
2503 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002504 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002505 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002506 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2507 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002508 xmlSchemaFreeFacet(facet);
2509 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002510 }
2511 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2512 xmlSchemaFreeFacet(facet);
2513 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002514 return (-1);
2515 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002516}
2517
2518/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002519 * xmlRelaxNGSchemaFreeValue:
2520 * @data: data needed for the library
2521 * @value: the value to free
2522 *
2523 * Function provided by a type library to free a Schemas value
2524 *
2525 * Returns 1 if yes, 0 if no and -1 in case of error.
2526 */
2527static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002528xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2529{
Daniel Veillard80b19092003-03-28 13:29:53 +00002530 xmlSchemaFreeValue(value);
2531}
2532
2533/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002534 * xmlRelaxNGSchemaTypeCompare:
2535 * @data: data needed for the library
2536 * @type: the type name
2537 * @value1: the first value
2538 * @value2: the second value
2539 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002540 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002541 * Datatype library.
2542 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002543 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002544 */
2545static int
2546xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002547 const xmlChar * type,
2548 const xmlChar * value1,
2549 xmlNodePtr ctxt1,
2550 void *comp1,
2551 const xmlChar * value2, xmlNodePtr ctxt2)
2552{
Daniel Veillard80b19092003-03-28 13:29:53 +00002553 int ret;
2554 xmlSchemaTypePtr typ;
2555 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2556
2557 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002558 return (-1);
2559 typ = xmlSchemaGetPredefinedType(type,
2560 BAD_CAST
2561 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002562 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002563 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002564 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002565 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2566 if (ret != 0)
2567 return (-1);
2568 if (res1 == NULL)
2569 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002570 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002571 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002572 }
2573 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002574 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002575 xmlSchemaFreeValue(res1);
2576 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002577 }
2578 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002579 xmlSchemaFreeValue(res1);
2580 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002581 }
2582 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002583 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002584 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002585 xmlSchemaFreeValue(res2);
2586 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002587 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002588 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002589 return (1);
2590 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002591}
Daniel Veillard4c004142003-10-07 11:33:24 +00002592
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002593/**
2594 * xmlRelaxNGDefaultTypeHave:
2595 * @data: data needed for the library
2596 * @type: the type name
2597 *
2598 * Check if the given type is provided by
2599 * the default datatype library.
2600 *
2601 * Returns 1 if yes, 0 if no and -1 in case of error.
2602 */
2603static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002604xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2605 const xmlChar * type)
2606{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002607 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002608 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002609 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002610 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002611 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002612 return (1);
2613 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002614}
2615
2616/**
2617 * xmlRelaxNGDefaultTypeCheck:
2618 * @data: data needed for the library
2619 * @type: the type name
2620 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002621 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002622 *
2623 * Check if the given type and value are validated by
2624 * the default datatype library.
2625 *
2626 * Returns 1 if yes, 0 if no and -1 in case of error.
2627 */
2628static int
2629xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002630 const xmlChar * type ATTRIBUTE_UNUSED,
2631 const xmlChar * value ATTRIBUTE_UNUSED,
2632 void **result ATTRIBUTE_UNUSED,
2633 xmlNodePtr node ATTRIBUTE_UNUSED)
2634{
Daniel Veillardd4310742003-02-18 21:12:46 +00002635 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002636 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002637 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002638 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002639 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002640 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002641 }
2642
Daniel Veillard4c004142003-10-07 11:33:24 +00002643 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002644}
2645
2646/**
2647 * xmlRelaxNGDefaultTypeCompare:
2648 * @data: data needed for the library
2649 * @type: the type name
2650 * @value1: the first value
2651 * @value2: the second value
2652 *
2653 * Compare two values accordingly a type from the default
2654 * datatype library.
2655 *
2656 * Returns 1 if yes, 0 if no and -1 in case of error.
2657 */
2658static int
2659xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002660 const xmlChar * type,
2661 const xmlChar * value1,
2662 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2663 void *comp1 ATTRIBUTE_UNUSED,
2664 const xmlChar * value2,
2665 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2666{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002667 int ret = -1;
2668
2669 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002670 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002671 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002672 if (!xmlStrEqual(value1, value2)) {
2673 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002674
Daniel Veillard4c004142003-10-07 11:33:24 +00002675 /*
2676 * TODO: trivial optimizations are possible by
2677 * computing at compile-time
2678 */
2679 nval = xmlRelaxNGNormalize(NULL, value1);
2680 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002681
Daniel Veillard4c004142003-10-07 11:33:24 +00002682 if ((nval == NULL) || (nvalue == NULL))
2683 ret = -1;
2684 else if (xmlStrEqual(nval, nvalue))
2685 ret = 1;
2686 else
2687 ret = 0;
2688 if (nval != NULL)
2689 xmlFree(nval);
2690 if (nvalue != NULL)
2691 xmlFree(nvalue);
2692 } else
2693 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002694 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002695 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002696}
Daniel Veillard4c004142003-10-07 11:33:24 +00002697
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002698static int xmlRelaxNGTypeInitialized = 0;
2699static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2700
2701/**
2702 * xmlRelaxNGFreeTypeLibrary:
2703 * @lib: the type library structure
2704 * @namespace: the URI bound to the library
2705 *
2706 * Free the structure associated to the type library
2707 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002708static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002709xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002710 const xmlChar * namespace ATTRIBUTE_UNUSED)
2711{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002712 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002713 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002714 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002715 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002716 xmlFree(lib);
2717}
2718
2719/**
2720 * xmlRelaxNGRegisterTypeLibrary:
2721 * @namespace: the URI bound to the library
2722 * @data: data associated to the library
2723 * @have: the provide function
2724 * @check: the checking function
2725 * @comp: the comparison function
2726 *
2727 * Register a new type library
2728 *
2729 * Returns 0 in case of success and -1 in case of error.
2730 */
2731static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002732xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2733 xmlRelaxNGTypeHave have,
2734 xmlRelaxNGTypeCheck check,
2735 xmlRelaxNGTypeCompare comp,
2736 xmlRelaxNGFacetCheck facet,
2737 xmlRelaxNGTypeFree freef)
2738{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002739 xmlRelaxNGTypeLibraryPtr lib;
2740 int ret;
2741
2742 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002743 (check == NULL) || (comp == NULL))
2744 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002745 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002746 xmlGenericError(xmlGenericErrorContext,
2747 "Relax-NG types library '%s' already registered\n",
2748 namespace);
2749 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002750 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002751 lib =
2752 (xmlRelaxNGTypeLibraryPtr)
2753 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002754 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002755 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002756 return (-1);
2757 }
2758 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2759 lib->namespace = xmlStrdup(namespace);
2760 lib->data = data;
2761 lib->have = have;
2762 lib->comp = comp;
2763 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002764 lib->facet = facet;
2765 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002766 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2767 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002768 xmlGenericError(xmlGenericErrorContext,
2769 "Relax-NG types library failed to register '%s'\n",
2770 namespace);
2771 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2772 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002773 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002774 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002775}
2776
2777/**
2778 * xmlRelaxNGInitTypes:
2779 *
2780 * Initilize the default type libraries.
2781 *
2782 * Returns 0 in case of success and -1 in case of error.
2783 */
2784static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002785xmlRelaxNGInitTypes(void)
2786{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002787 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002788 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002789 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2790 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002791 xmlGenericError(xmlGenericErrorContext,
2792 "Failed to allocate sh table for Relax-NG types\n");
2793 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002794 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002795 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2796 "http://www.w3.org/2001/XMLSchema-datatypes",
2797 NULL, xmlRelaxNGSchemaTypeHave,
2798 xmlRelaxNGSchemaTypeCheck,
2799 xmlRelaxNGSchemaTypeCompare,
2800 xmlRelaxNGSchemaFacetCheck,
2801 xmlRelaxNGSchemaFreeValue);
2802 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2803 xmlRelaxNGDefaultTypeHave,
2804 xmlRelaxNGDefaultTypeCheck,
2805 xmlRelaxNGDefaultTypeCompare, NULL,
2806 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002807 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002808 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002809}
2810
2811/**
2812 * xmlRelaxNGCleanupTypes:
2813 *
2814 * Cleanup the default Schemas type library associated to RelaxNG
2815 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002816void
2817xmlRelaxNGCleanupTypes(void)
2818{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002819 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002820 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002821 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002822 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002823 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002824 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002825}
2826
2827/************************************************************************
2828 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002829 * Compiling element content into regexp *
2830 * *
2831 * Sometime the element content can be compiled into a pure regexp, *
2832 * This allows a faster execution and streamability at that level *
2833 * *
2834 ************************************************************************/
2835
Daniel Veillard52b48c72003-04-13 19:53:42 +00002836static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2837 xmlRelaxNGDefinePtr def);
2838
Daniel Veillard952379b2003-03-17 15:37:12 +00002839/**
2840 * xmlRelaxNGIsCompileable:
2841 * @define: the definition to check
2842 *
2843 * Check if a definition is nullable.
2844 *
2845 * Returns 1 if yes, 0 if no and -1 in case of error
2846 */
2847static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002848xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2849{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002850 int ret = -1;
2851
Daniel Veillard952379b2003-03-17 15:37:12 +00002852 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002853 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002854 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002855 if ((def->type != XML_RELAXNG_ELEMENT) &&
2856 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002857 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002858 if ((def->type != XML_RELAXNG_ELEMENT) &&
2859 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002860 return (0);
2861 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002862 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002863 ret = xmlRelaxNGIsCompileable(def->content);
2864 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002865 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002866 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002867 ret = 1;
2868 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002869 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002870 /*
2871 * Check if the element content is compileable
2872 */
2873 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2874 ((def->dflags & IS_COMPILABLE) == 0)) {
2875 xmlRelaxNGDefinePtr list;
2876
2877 list = def->content;
2878 while (list != NULL) {
2879 ret = xmlRelaxNGIsCompileable(list);
2880 if (ret != 1)
2881 break;
2882 list = list->next;
2883 }
William M. Brack60929622004-03-27 17:54:18 +00002884 /*
2885 * Because the routine is recursive, we must guard against
2886 * discovering both COMPILABLE and NOT_COMPILABLE
2887 */
2888 if (ret == 0) {
2889 def->dflags &= ~IS_COMPILABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002890 def->dflags |= IS_NOT_COMPILABLE;
William M. Brack60929622004-03-27 17:54:18 +00002891 }
2892 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002893 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002894#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002895 if (ret == 1) {
2896 xmlGenericError(xmlGenericErrorContext,
2897 "element content for %s is compilable\n",
2898 def->name);
2899 } else if (ret == 0) {
2900 xmlGenericError(xmlGenericErrorContext,
2901 "element content for %s is not compilable\n",
2902 def->name);
2903 } else {
2904 xmlGenericError(xmlGenericErrorContext,
2905 "Problem in RelaxNGIsCompileable for element %s\n",
2906 def->name);
2907 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002908#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002909 }
2910 /*
2911 * All elements return a compileable status unless they
2912 * are generic like anyName
2913 */
2914 if ((def->nameClass != NULL) || (def->name == NULL))
2915 ret = 0;
2916 else
2917 ret = 1;
2918 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002919 case XML_RELAXNG_REF:
2920 case XML_RELAXNG_EXTERNALREF:
2921 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002922 if (def->depth == -20) {
2923 return (1);
2924 } else {
2925 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002926
Daniel Veillard4c004142003-10-07 11:33:24 +00002927 def->depth = -20;
2928 list = def->content;
2929 while (list != NULL) {
2930 ret = xmlRelaxNGIsCompileable(list);
2931 if (ret != 1)
2932 break;
2933 list = list->next;
2934 }
2935 }
2936 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002937 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002938 case XML_RELAXNG_OPTIONAL:
2939 case XML_RELAXNG_ZEROORMORE:
2940 case XML_RELAXNG_ONEORMORE:
2941 case XML_RELAXNG_CHOICE:
2942 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002943 case XML_RELAXNG_DEF:{
2944 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002945
Daniel Veillard4c004142003-10-07 11:33:24 +00002946 list = def->content;
2947 while (list != NULL) {
2948 ret = xmlRelaxNGIsCompileable(list);
2949 if (ret != 1)
2950 break;
2951 list = list->next;
2952 }
2953 break;
2954 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002955 case XML_RELAXNG_EXCEPT:
2956 case XML_RELAXNG_ATTRIBUTE:
2957 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002958 case XML_RELAXNG_DATATYPE:
2959 case XML_RELAXNG_LIST:
2960 case XML_RELAXNG_PARAM:
2961 case XML_RELAXNG_VALUE:
Daniel Veillard952379b2003-03-17 15:37:12 +00002962 case XML_RELAXNG_NOT_ALLOWED:
William M. Brack7e29c0a2004-04-02 09:07:22 +00002963 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002964 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002965 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002966 if (ret == 0)
2967 def->dflags |= IS_NOT_COMPILABLE;
2968 if (ret == 1)
2969 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002970#ifdef DEBUG_COMPILE
2971 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002972 xmlGenericError(xmlGenericErrorContext,
2973 "RelaxNGIsCompileable %s : true\n",
2974 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002975 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002976 xmlGenericError(xmlGenericErrorContext,
2977 "RelaxNGIsCompileable %s : false\n",
2978 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002979 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002980 xmlGenericError(xmlGenericErrorContext,
2981 "Problem in RelaxNGIsCompileable %s\n",
2982 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002983 }
2984#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002985 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002986}
2987
2988/**
2989 * xmlRelaxNGCompile:
2990 * ctxt: the RelaxNG parser context
2991 * @define: the definition tree to compile
2992 *
2993 * Compile the set of definitions, it works recursively, till the
2994 * element boundaries, where it tries to compile the content if possible
2995 *
2996 * Returns 0 if success and -1 in case of error
2997 */
2998static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002999xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3000{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003001 int ret = 0;
3002 xmlRelaxNGDefinePtr list;
3003
Daniel Veillard4c004142003-10-07 11:33:24 +00003004 if ((ctxt == NULL) || (def == NULL))
3005 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003006
Daniel Veillard4c004142003-10-07 11:33:24 +00003007 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003008 case XML_RELAXNG_START:
3009 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003010 xmlAutomataPtr oldam = ctxt->am;
3011 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003012
3013 def->depth = -25;
3014
Daniel Veillard4c004142003-10-07 11:33:24 +00003015 list = def->content;
3016 ctxt->am = xmlNewAutomata();
3017 if (ctxt->am == NULL)
3018 return (-1);
3019 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3020 while (list != NULL) {
3021 xmlRelaxNGCompile(ctxt, list);
3022 list = list->next;
3023 }
3024 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3025 def->contModel = xmlAutomataCompile(ctxt->am);
3026 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003027
Daniel Veillard4c004142003-10-07 11:33:24 +00003028 xmlFreeAutomata(ctxt->am);
3029 ctxt->state = oldstate;
3030 ctxt->am = oldam;
3031 }
3032 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003033 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003034 if ((ctxt->am != NULL) && (def->name != NULL)) {
3035 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3036 ctxt->state, NULL,
3037 def->name, def->ns,
3038 def);
3039 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003040 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003041 xmlAutomataPtr oldam = ctxt->am;
3042 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003043
3044 def->depth = -25;
3045
Daniel Veillard4c004142003-10-07 11:33:24 +00003046 list = def->content;
3047 ctxt->am = xmlNewAutomata();
3048 if (ctxt->am == NULL)
3049 return (-1);
3050 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3051 while (list != NULL) {
3052 xmlRelaxNGCompile(ctxt, list);
3053 list = list->next;
3054 }
3055 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3056 def->contModel = xmlAutomataCompile(ctxt->am);
3057 if (!xmlRegexpIsDeterminist(def->contModel)) {
3058 /*
3059 * we can only use the automata if it is determinist
3060 */
3061 xmlRegFreeRegexp(def->contModel);
3062 def->contModel = NULL;
3063 }
3064 xmlFreeAutomata(ctxt->am);
3065 ctxt->state = oldstate;
3066 ctxt->am = oldam;
3067 } else {
3068 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003069
Daniel Veillard4c004142003-10-07 11:33:24 +00003070 /*
3071 * we can't build the content model for this element content
3072 * but it still might be possible to build it for some of its
3073 * children, recurse.
3074 */
3075 ret = xmlRelaxNGTryCompile(ctxt, def);
3076 ctxt->am = oldam;
3077 }
3078 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003079 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003080 ret = xmlRelaxNGCompile(ctxt, def->content);
3081 break;
3082 case XML_RELAXNG_OPTIONAL:{
3083 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003084
Daniel Veillard4c004142003-10-07 11:33:24 +00003085 xmlRelaxNGCompile(ctxt, def->content);
3086 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3087 break;
3088 }
3089 case XML_RELAXNG_ZEROORMORE:{
3090 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003091
Daniel Veillard4c004142003-10-07 11:33:24 +00003092 ctxt->state =
3093 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3094 oldstate = ctxt->state;
3095 list = def->content;
3096 while (list != NULL) {
3097 xmlRelaxNGCompile(ctxt, list);
3098 list = list->next;
3099 }
3100 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3101 ctxt->state =
3102 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3103 break;
3104 }
3105 case XML_RELAXNG_ONEORMORE:{
3106 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003107
Daniel Veillard4c004142003-10-07 11:33:24 +00003108 list = def->content;
3109 while (list != NULL) {
3110 xmlRelaxNGCompile(ctxt, list);
3111 list = list->next;
3112 }
3113 oldstate = ctxt->state;
3114 list = def->content;
3115 while (list != NULL) {
3116 xmlRelaxNGCompile(ctxt, list);
3117 list = list->next;
3118 }
3119 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3120 ctxt->state =
3121 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3122 break;
3123 }
3124 case XML_RELAXNG_CHOICE:{
3125 xmlAutomataStatePtr target = NULL;
3126 xmlAutomataStatePtr oldstate = ctxt->state;
3127
3128 list = def->content;
3129 while (list != NULL) {
3130 ctxt->state = oldstate;
3131 ret = xmlRelaxNGCompile(ctxt, list);
3132 if (ret != 0)
3133 break;
3134 if (target == NULL)
3135 target = ctxt->state;
3136 else {
3137 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3138 target);
3139 }
3140 list = list->next;
3141 }
3142 ctxt->state = target;
3143
3144 break;
3145 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003146 case XML_RELAXNG_REF:
3147 case XML_RELAXNG_EXTERNALREF:
3148 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003149 case XML_RELAXNG_GROUP:
3150 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003151 list = def->content;
3152 while (list != NULL) {
3153 ret = xmlRelaxNGCompile(ctxt, list);
3154 if (ret != 0)
3155 break;
3156 list = list->next;
3157 }
3158 break;
3159 case XML_RELAXNG_TEXT:{
3160 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003161
Daniel Veillard4c004142003-10-07 11:33:24 +00003162 ctxt->state =
3163 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3164 oldstate = ctxt->state;
3165 xmlRelaxNGCompile(ctxt, def->content);
3166 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3167 ctxt->state, BAD_CAST "#text",
3168 NULL);
3169 ctxt->state =
3170 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3171 break;
3172 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003173 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003174 ctxt->state =
3175 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3176 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003177 case XML_RELAXNG_EXCEPT:
3178 case XML_RELAXNG_ATTRIBUTE:
3179 case XML_RELAXNG_INTERLEAVE:
3180 case XML_RELAXNG_NOT_ALLOWED:
3181 case XML_RELAXNG_DATATYPE:
3182 case XML_RELAXNG_LIST:
3183 case XML_RELAXNG_PARAM:
3184 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003185 /* This should not happen and generate an internal error */
3186 fprintf(stderr, "RNG internal error trying to compile %s\n",
3187 xmlRelaxNGDefName(def));
3188 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003189 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003190 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003191}
3192
3193/**
3194 * xmlRelaxNGTryCompile:
3195 * ctxt: the RelaxNG parser context
3196 * @define: the definition tree to compile
3197 *
3198 * Try to compile the set of definitions, it works recursively,
3199 * possibly ignoring parts which cannot be compiled.
3200 *
3201 * Returns 0 if success and -1 in case of error
3202 */
3203static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003204xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3205{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003206 int ret = 0;
3207 xmlRelaxNGDefinePtr list;
3208
Daniel Veillard4c004142003-10-07 11:33:24 +00003209 if ((ctxt == NULL) || (def == NULL))
3210 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003211
3212 if ((def->type == XML_RELAXNG_START) ||
3213 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003214 ret = xmlRelaxNGIsCompileable(def);
3215 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3216 ctxt->am = NULL;
3217 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003218#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003219 if (ret == 0) {
3220 if (def->type == XML_RELAXNG_START)
3221 xmlGenericError(xmlGenericErrorContext,
3222 "compiled the start\n");
3223 else
3224 xmlGenericError(xmlGenericErrorContext,
3225 "compiled element %s\n", def->name);
3226 } else {
3227 if (def->type == XML_RELAXNG_START)
3228 xmlGenericError(xmlGenericErrorContext,
3229 "failed to compile the start\n");
3230 else
3231 xmlGenericError(xmlGenericErrorContext,
3232 "failed to compile element %s\n",
3233 def->name);
3234 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003235#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003236 return (ret);
3237 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003238 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003239 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003240 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003241 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3242 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003243 case XML_RELAXNG_TEXT:
3244 case XML_RELAXNG_DATATYPE:
3245 case XML_RELAXNG_LIST:
3246 case XML_RELAXNG_PARAM:
3247 case XML_RELAXNG_VALUE:
3248 case XML_RELAXNG_EMPTY:
3249 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003250 ret = 0;
3251 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003252 case XML_RELAXNG_OPTIONAL:
3253 case XML_RELAXNG_ZEROORMORE:
3254 case XML_RELAXNG_ONEORMORE:
3255 case XML_RELAXNG_CHOICE:
3256 case XML_RELAXNG_GROUP:
3257 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003258 case XML_RELAXNG_START:
3259 case XML_RELAXNG_REF:
3260 case XML_RELAXNG_EXTERNALREF:
3261 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003262 list = def->content;
3263 while (list != NULL) {
3264 ret = xmlRelaxNGTryCompile(ctxt, list);
3265 if (ret != 0)
3266 break;
3267 list = list->next;
3268 }
3269 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003270 case XML_RELAXNG_EXCEPT:
3271 case XML_RELAXNG_ATTRIBUTE:
3272 case XML_RELAXNG_INTERLEAVE:
3273 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003274 ret = 0;
3275 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003276 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003277 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003278}
3279
3280/************************************************************************
3281 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003282 * Parsing functions *
3283 * *
3284 ************************************************************************/
3285
Daniel Veillard4c004142003-10-07 11:33:24 +00003286static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3287 ctxt, xmlNodePtr node);
3288static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3289 ctxt, xmlNodePtr node);
3290static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3291 ctxt, xmlNodePtr nodes,
3292 int group);
3293static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3294 ctxt, xmlNodePtr node);
3295static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3296 xmlNodePtr node);
3297static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3298 xmlNodePtr nodes);
3299static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3300 ctxt, xmlNodePtr node,
3301 xmlRelaxNGDefinePtr
3302 def);
3303static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3304 ctxt, xmlNodePtr nodes);
3305static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3306 xmlRelaxNGDefinePtr define,
3307 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003308
3309
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003310#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003311
3312/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003313 * xmlRelaxNGIsNullable:
3314 * @define: the definition to verify
3315 *
3316 * Check if a definition is nullable.
3317 *
3318 * Returns 1 if yes, 0 if no and -1 in case of error
3319 */
3320static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003321xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3322{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003323 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003324
Daniel Veillardfd573f12003-03-16 17:52:32 +00003325 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003326 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003327
Daniel Veillarde063f482003-03-21 16:53:17 +00003328 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003329 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003330 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003331 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003332 switch (define->type) {
3333 case XML_RELAXNG_EMPTY:
3334 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003335 ret = 1;
3336 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003337 case XML_RELAXNG_NOOP:
3338 case XML_RELAXNG_DEF:
3339 case XML_RELAXNG_REF:
3340 case XML_RELAXNG_EXTERNALREF:
3341 case XML_RELAXNG_PARENTREF:
3342 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003343 ret = xmlRelaxNGIsNullable(define->content);
3344 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003345 case XML_RELAXNG_EXCEPT:
3346 case XML_RELAXNG_NOT_ALLOWED:
3347 case XML_RELAXNG_ELEMENT:
3348 case XML_RELAXNG_DATATYPE:
3349 case XML_RELAXNG_PARAM:
3350 case XML_RELAXNG_VALUE:
3351 case XML_RELAXNG_LIST:
3352 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003353 ret = 0;
3354 break;
3355 case XML_RELAXNG_CHOICE:{
3356 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003357
Daniel Veillard4c004142003-10-07 11:33:24 +00003358 while (list != NULL) {
3359 ret = xmlRelaxNGIsNullable(list);
3360 if (ret != 0)
3361 goto done;
3362 list = list->next;
3363 }
3364 ret = 0;
3365 break;
3366 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003367 case XML_RELAXNG_START:
3368 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003369 case XML_RELAXNG_GROUP:{
3370 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003371
Daniel Veillard4c004142003-10-07 11:33:24 +00003372 while (list != NULL) {
3373 ret = xmlRelaxNGIsNullable(list);
3374 if (ret != 1)
3375 goto done;
3376 list = list->next;
3377 }
3378 return (1);
3379 }
3380 default:
3381 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003382 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003383 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003384 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003385 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003386 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003387 define->dflags |= IS_NULLABLE;
3388 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003389}
3390
3391/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003392 * xmlRelaxNGIsBlank:
3393 * @str: a string
3394 *
3395 * Check if a string is ignorable c.f. 4.2. Whitespace
3396 *
3397 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3398 */
3399static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003400xmlRelaxNGIsBlank(xmlChar * str)
3401{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003402 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003403 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003404 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003405 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003406 return (0);
3407 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003408 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003409 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003410}
3411
Daniel Veillard6eadf632003-01-23 18:29:16 +00003412/**
3413 * xmlRelaxNGGetDataTypeLibrary:
3414 * @ctxt: a Relax-NG parser context
3415 * @node: the current data or value element
3416 *
3417 * Applies algorithm from 4.3. datatypeLibrary attribute
3418 *
3419 * Returns the datatypeLibary value or NULL if not found
3420 */
3421static xmlChar *
3422xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003423 xmlNodePtr node)
3424{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003425 xmlChar *ret, *escape;
3426
Daniel Veillard6eadf632003-01-23 18:29:16 +00003427 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003428 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3429 if (ret != NULL) {
3430 if (ret[0] == 0) {
3431 xmlFree(ret);
3432 return (NULL);
3433 }
3434 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3435 if (escape == NULL) {
3436 return (ret);
3437 }
3438 xmlFree(ret);
3439 return (escape);
3440 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003441 }
3442 node = node->parent;
3443 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003444 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3445 if (ret != NULL) {
3446 if (ret[0] == 0) {
3447 xmlFree(ret);
3448 return (NULL);
3449 }
3450 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3451 if (escape == NULL) {
3452 return (ret);
3453 }
3454 xmlFree(ret);
3455 return (escape);
3456 }
3457 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003458 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003459 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003460}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003461
3462/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003463 * xmlRelaxNGParseValue:
3464 * @ctxt: a Relax-NG parser context
3465 * @node: the data node.
3466 *
3467 * parse the content of a RelaxNG value node.
3468 *
3469 * Returns the definition pointer or NULL in case of error
3470 */
3471static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003472xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3473{
Daniel Veillardedc91922003-01-26 00:52:04 +00003474 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003475 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003476 xmlChar *type;
3477 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003478 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003479
Daniel Veillardfd573f12003-03-16 17:52:32 +00003480 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003481 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003482 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003483 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003484
3485 type = xmlGetProp(node, BAD_CAST "type");
3486 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003487 xmlRelaxNGNormExtSpace(type);
3488 if (xmlValidateNCName(type, 0)) {
3489 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3490 "value type '%s' is not an NCName\n", type, NULL);
3491 }
3492 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3493 if (library == NULL)
3494 library =
3495 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003496
Daniel Veillard4c004142003-10-07 11:33:24 +00003497 def->name = type;
3498 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003499
Daniel Veillard4c004142003-10-07 11:33:24 +00003500 lib = (xmlRelaxNGTypeLibraryPtr)
3501 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3502 if (lib == NULL) {
3503 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3504 "Use of unregistered type library '%s'\n", library,
3505 NULL);
3506 def->data = NULL;
3507 } else {
3508 def->data = lib;
3509 if (lib->have == NULL) {
3510 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3511 "Internal error with type library '%s': no 'have'\n",
3512 library, NULL);
3513 } else {
3514 success = lib->have(lib->data, def->name);
3515 if (success != 1) {
3516 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3517 "Error type '%s' is not exported by type library '%s'\n",
3518 def->name, library);
3519 }
3520 }
3521 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003522 }
3523 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003524 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003525 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003526 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3527 (node->children->next != NULL)) {
3528 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3529 "Expecting a single text value for <value>content\n",
3530 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003531 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003532 def->value = xmlNodeGetContent(node);
3533 if (def->value == NULL) {
3534 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3535 "Element <value> has no content\n", NULL, NULL);
3536 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3537 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003538
Daniel Veillard4c004142003-10-07 11:33:24 +00003539 success =
3540 lib->check(lib->data, def->name, def->value, &val, node);
3541 if (success != 1) {
3542 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3543 "Value '%s' is not acceptable for type '%s'\n",
3544 def->value, def->name);
3545 } else {
3546 if (val != NULL)
3547 def->attrs = val;
3548 }
3549 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003550 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003551 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003552}
3553
3554/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003555 * xmlRelaxNGParseData:
3556 * @ctxt: a Relax-NG parser context
3557 * @node: the data node.
3558 *
3559 * parse the content of a RelaxNG data node.
3560 *
3561 * Returns the definition pointer or NULL in case of error
3562 */
3563static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003564xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3565{
Daniel Veillard416589a2003-02-17 17:25:42 +00003566 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003567 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003568 xmlRelaxNGTypeLibraryPtr lib;
3569 xmlChar *type;
3570 xmlChar *library;
3571 xmlNodePtr content;
3572 int tmp;
3573
3574 type = xmlGetProp(node, BAD_CAST "type");
3575 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003576 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3577 NULL);
3578 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003579 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003580 xmlRelaxNGNormExtSpace(type);
3581 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003582 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3583 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003584 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003585 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3586 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003587 library =
3588 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003589
Daniel Veillardfd573f12003-03-16 17:52:32 +00003590 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003591 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003592 xmlFree(type);
3593 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003594 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003595 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003596 def->name = type;
3597 def->ns = library;
3598
3599 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003600 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003601 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003602 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3603 "Use of unregistered type library '%s'\n", library,
3604 NULL);
3605 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003606 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003607 def->data = lib;
3608 if (lib->have == NULL) {
3609 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3610 "Internal error with type library '%s': no 'have'\n",
3611 library, NULL);
3612 } else {
3613 tmp = lib->have(lib->data, def->name);
3614 if (tmp != 1) {
3615 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3616 "Error type '%s' is not exported by type library '%s'\n",
3617 def->name, library);
3618 } else
3619 if ((xmlStrEqual
3620 (library,
3621 BAD_CAST
3622 "http://www.w3.org/2001/XMLSchema-datatypes"))
3623 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3624 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3625 ctxt->idref = 1;
3626 }
3627 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003628 }
3629 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003630
3631 /*
3632 * Handle optional params
3633 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003634 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003635 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3636 break;
3637 if (xmlStrEqual(library,
3638 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3639 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3640 "Type library '%s' does not allow type parameters\n",
3641 library, NULL);
3642 content = content->next;
3643 while ((content != NULL) &&
3644 (xmlStrEqual(content->name, BAD_CAST "param")))
3645 content = content->next;
3646 } else {
3647 param = xmlRelaxNGNewDefine(ctxt, node);
3648 if (param != NULL) {
3649 param->type = XML_RELAXNG_PARAM;
3650 param->name = xmlGetProp(content, BAD_CAST "name");
3651 if (param->name == NULL) {
3652 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3653 "param has no name\n", NULL, NULL);
3654 }
3655 param->value = xmlNodeGetContent(content);
3656 if (lastparam == NULL) {
3657 def->attrs = lastparam = param;
3658 } else {
3659 lastparam->next = param;
3660 lastparam = param;
3661 }
3662 if (lib != NULL) {
3663 }
3664 }
3665 content = content->next;
3666 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003667 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003668 /*
3669 * Handle optional except
3670 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003671 if ((content != NULL)
3672 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3673 xmlNodePtr child;
3674 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003675
Daniel Veillard4c004142003-10-07 11:33:24 +00003676 except = xmlRelaxNGNewDefine(ctxt, node);
3677 if (except == NULL) {
3678 return (def);
3679 }
3680 except->type = XML_RELAXNG_EXCEPT;
3681 child = content->children;
3682 if (last == NULL) {
3683 def->content = except;
3684 } else {
3685 last->next = except;
3686 }
3687 if (child == NULL) {
3688 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3689 "except has no content\n", NULL, NULL);
3690 }
3691 while (child != NULL) {
3692 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3693 if (tmp2 != NULL) {
3694 if (last2 == NULL) {
3695 except->content = last2 = tmp2;
3696 } else {
3697 last2->next = tmp2;
3698 last2 = tmp2;
3699 }
3700 }
3701 child = child->next;
3702 }
3703 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003704 }
3705 /*
3706 * Check there is no unhandled data
3707 */
3708 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003709 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3710 "Element data has unexpected content %s\n",
3711 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003712 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003713
Daniel Veillard4c004142003-10-07 11:33:24 +00003714 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003715}
3716
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003717static const xmlChar *invalidName = BAD_CAST "\1";
3718
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003719/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003720 * xmlRelaxNGCompareNameClasses:
3721 * @defs1: the first element/attribute defs
3722 * @defs2: the second element/attribute defs
3723 * @name: the restriction on the name
3724 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003725 *
3726 * Compare the 2 lists of element definitions. The comparison is
3727 * that if both lists do not accept the same QNames, it returns 1
3728 * If the 2 lists can accept the same QName the comparison returns 0
3729 *
3730 * Returns 1 disttinct, 0 if equal
3731 */
3732static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003733xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003734 xmlRelaxNGDefinePtr def2)
3735{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003736 int ret = 1;
3737 xmlNode node;
3738 xmlNs ns;
3739 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003740
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003741 ctxt.flags = FLAGS_IGNORABLE;
3742
Daniel Veillard42f12e92003-03-07 18:32:59 +00003743 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3744
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003745 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003746 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3747 if (def2->type == XML_RELAXNG_TEXT)
3748 return (1);
3749 if (def1->name != NULL) {
3750 node.name = def1->name;
3751 } else {
3752 node.name = invalidName;
3753 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003754 if (def1->ns != NULL) {
3755 if (def1->ns[0] == 0) {
3756 node.ns = NULL;
3757 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003758 node.ns = &ns;
Daniel Veillard4c004142003-10-07 11:33:24 +00003759 ns.href = def1->ns;
3760 }
3761 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003762 node.ns = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00003763 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003764 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003765 if (def1->nameClass != NULL) {
3766 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3767 } else {
3768 ret = 0;
3769 }
3770 } else {
3771 ret = 1;
3772 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003773 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003774 if (def2->type == XML_RELAXNG_TEXT)
3775 return (0);
3776 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003777 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003778 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003779 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003780 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003781 }
3782 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003783 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003784 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003785 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3786 if (def2->name != NULL) {
3787 node.name = def2->name;
3788 } else {
3789 node.name = invalidName;
3790 }
3791 node.ns = &ns;
3792 if (def2->ns != NULL) {
3793 if (def2->ns[0] == 0) {
3794 node.ns = NULL;
3795 } else {
3796 ns.href = def2->ns;
3797 }
3798 } else {
3799 ns.href = invalidName;
3800 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003801 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003802 if (def2->nameClass != NULL) {
3803 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3804 } else {
3805 ret = 0;
3806 }
3807 } else {
3808 ret = 1;
3809 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003810 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003811 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003812 }
3813
Daniel Veillard4c004142003-10-07 11:33:24 +00003814 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003815}
3816
3817/**
3818 * xmlRelaxNGCompareElemDefLists:
3819 * @ctxt: a Relax-NG parser context
3820 * @defs1: the first list of element/attribute defs
3821 * @defs2: the second list of element/attribute defs
3822 *
3823 * Compare the 2 lists of element or attribute definitions. The comparison
3824 * is that if both lists do not accept the same QNames, it returns 1
3825 * If the 2 lists can accept the same QName the comparison returns 0
3826 *
3827 * Returns 1 disttinct, 0 if equal
3828 */
3829static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003830xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3831 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3832 xmlRelaxNGDefinePtr * def2)
3833{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003834 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003835
Daniel Veillard154877e2003-01-30 12:17:05 +00003836 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003837 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003838 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003839 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003840 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003841 while ((*def2) != NULL) {
3842 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3843 return (0);
3844 def2++;
3845 }
3846 def2 = basedef2;
3847 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003848 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003849 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003850}
3851
3852/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003853 * xmlRelaxNGGenerateAttributes:
3854 * @ctxt: a Relax-NG parser context
3855 * @def: the definition definition
3856 *
3857 * Check if the definition can only generate attributes
3858 *
3859 * Returns 1 if yes, 0 if no and -1 in case of error.
3860 */
3861static int
3862xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003863 xmlRelaxNGDefinePtr def)
3864{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003865 xmlRelaxNGDefinePtr parent, cur, tmp;
3866
3867 /*
3868 * Don't run that check in case of error. Infinite recursion
3869 * becomes possible.
3870 */
3871 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003872 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003873
3874 parent = NULL;
3875 cur = def;
3876 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003877 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3878 (cur->type == XML_RELAXNG_TEXT) ||
3879 (cur->type == XML_RELAXNG_DATATYPE) ||
3880 (cur->type == XML_RELAXNG_PARAM) ||
3881 (cur->type == XML_RELAXNG_LIST) ||
3882 (cur->type == XML_RELAXNG_VALUE) ||
3883 (cur->type == XML_RELAXNG_EMPTY))
3884 return (0);
3885 if ((cur->type == XML_RELAXNG_CHOICE) ||
3886 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3887 (cur->type == XML_RELAXNG_GROUP) ||
3888 (cur->type == XML_RELAXNG_ONEORMORE) ||
3889 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3890 (cur->type == XML_RELAXNG_OPTIONAL) ||
3891 (cur->type == XML_RELAXNG_PARENTREF) ||
3892 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3893 (cur->type == XML_RELAXNG_REF) ||
3894 (cur->type == XML_RELAXNG_DEF)) {
3895 if (cur->content != NULL) {
3896 parent = cur;
3897 cur = cur->content;
3898 tmp = cur;
3899 while (tmp != NULL) {
3900 tmp->parent = parent;
3901 tmp = tmp->next;
3902 }
3903 continue;
3904 }
3905 }
3906 if (cur == def)
3907 break;
3908 if (cur->next != NULL) {
3909 cur = cur->next;
3910 continue;
3911 }
3912 do {
3913 cur = cur->parent;
3914 if (cur == NULL)
3915 break;
3916 if (cur == def)
3917 return (1);
3918 if (cur->next != NULL) {
3919 cur = cur->next;
3920 break;
3921 }
3922 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003923 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003924 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003925}
Daniel Veillard4c004142003-10-07 11:33:24 +00003926
Daniel Veillardce192eb2003-04-16 15:58:05 +00003927/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003928 * xmlRelaxNGGetElements:
3929 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003930 * @def: the definition definition
3931 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003932 *
3933 * Compute the list of top elements a definition can generate
3934 *
3935 * Returns a list of elements or NULL if none was found.
3936 */
3937static xmlRelaxNGDefinePtr *
3938xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003939 xmlRelaxNGDefinePtr def, int eora)
3940{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003941 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003942 int len = 0;
3943 int max = 0;
3944
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003945 /*
3946 * Don't run that check in case of error. Infinite recursion
3947 * becomes possible.
3948 */
3949 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003950 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003951
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003952 parent = NULL;
3953 cur = def;
3954 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003955 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3956 (cur->type == XML_RELAXNG_TEXT))) ||
3957 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3958 if (ret == NULL) {
3959 max = 10;
3960 ret = (xmlRelaxNGDefinePtr *)
3961 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3962 if (ret == NULL) {
3963 xmlRngPErrMemory(ctxt, "getting element list\n");
3964 return (NULL);
3965 }
3966 } else if (max <= len) {
Daniel Veillard079f6a72004-09-23 13:15:03 +00003967 xmlRelaxNGDefinePtr *temp;
3968
Daniel Veillard4c004142003-10-07 11:33:24 +00003969 max *= 2;
Daniel Veillard079f6a72004-09-23 13:15:03 +00003970 temp = xmlRealloc(ret,
Daniel Veillard4c004142003-10-07 11:33:24 +00003971 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
Daniel Veillard079f6a72004-09-23 13:15:03 +00003972 if (temp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003973 xmlRngPErrMemory(ctxt, "getting element list\n");
Daniel Veillard079f6a72004-09-23 13:15:03 +00003974 xmlFree(ret);
Daniel Veillard4c004142003-10-07 11:33:24 +00003975 return (NULL);
3976 }
Daniel Veillard079f6a72004-09-23 13:15:03 +00003977 ret = temp;
Daniel Veillard4c004142003-10-07 11:33:24 +00003978 }
3979 ret[len++] = cur;
3980 ret[len] = NULL;
3981 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3982 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3983 (cur->type == XML_RELAXNG_GROUP) ||
3984 (cur->type == XML_RELAXNG_ONEORMORE) ||
3985 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3986 (cur->type == XML_RELAXNG_OPTIONAL) ||
3987 (cur->type == XML_RELAXNG_PARENTREF) ||
3988 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00003989 (cur->type == XML_RELAXNG_DEF) ||
3990 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003991 /*
3992 * Don't go within elements or attributes or string values.
3993 * Just gather the element top list
3994 */
3995 if (cur->content != NULL) {
3996 parent = cur;
3997 cur = cur->content;
3998 tmp = cur;
3999 while (tmp != NULL) {
4000 tmp->parent = parent;
4001 tmp = tmp->next;
4002 }
4003 continue;
4004 }
4005 }
4006 if (cur == def)
4007 break;
4008 if (cur->next != NULL) {
4009 cur = cur->next;
4010 continue;
4011 }
4012 do {
4013 cur = cur->parent;
4014 if (cur == NULL)
4015 break;
4016 if (cur == def)
4017 return (ret);
4018 if (cur->next != NULL) {
4019 cur = cur->next;
4020 break;
4021 }
4022 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004023 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004024 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004025}
Daniel Veillard4c004142003-10-07 11:33:24 +00004026
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004027/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004028 * xmlRelaxNGCheckChoiceDeterminism:
4029 * @ctxt: a Relax-NG parser context
4030 * @def: the choice definition
4031 *
4032 * Also used to find indeterministic pattern in choice
4033 */
4034static void
4035xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004036 xmlRelaxNGDefinePtr def)
4037{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004038 xmlRelaxNGDefinePtr **list;
4039 xmlRelaxNGDefinePtr cur;
4040 int nbchild = 0, i, j, ret;
4041 int is_nullable = 0;
4042 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004043 xmlHashTablePtr triage = NULL;
4044 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004045
Daniel Veillard4c004142003-10-07 11:33:24 +00004046 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4047 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004048
Daniel Veillarde063f482003-03-21 16:53:17 +00004049 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004050 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004051
Daniel Veillardfd573f12003-03-16 17:52:32 +00004052 /*
4053 * Don't run that check in case of error. Infinite recursion
4054 * becomes possible.
4055 */
4056 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004057 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004058
4059 is_nullable = xmlRelaxNGIsNullable(def);
4060
4061 cur = def->content;
4062 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004063 nbchild++;
4064 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004065 }
4066
4067 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004068 sizeof(xmlRelaxNGDefinePtr
4069 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004070 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004071 xmlRngPErrMemory(ctxt, "building choice\n");
4072 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004073 }
4074 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004075 /*
4076 * a bit strong but safe
4077 */
4078 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004079 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004080 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004081 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004082 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004083 cur = def->content;
4084 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004085 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4086 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4087 is_triable = 0;
4088 } else if (is_triable == 1) {
4089 xmlRelaxNGDefinePtr *tmp;
4090 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004091
Daniel Veillard4c004142003-10-07 11:33:24 +00004092 tmp = list[i];
4093 while ((*tmp != NULL) && (is_triable == 1)) {
4094 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4095 res = xmlHashAddEntry2(triage,
4096 BAD_CAST "#text", NULL,
4097 (void *) cur);
4098 if (res != 0)
4099 is_triable = -1;
4100 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4101 ((*tmp)->name != NULL)) {
4102 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4103 res = xmlHashAddEntry2(triage,
4104 (*tmp)->name, NULL,
4105 (void *) cur);
4106 else
4107 res = xmlHashAddEntry2(triage,
4108 (*tmp)->name, (*tmp)->ns,
4109 (void *) cur);
4110 if (res != 0)
4111 is_triable = -1;
4112 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4113 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4114 res = xmlHashAddEntry2(triage,
4115 BAD_CAST "#any", NULL,
4116 (void *) cur);
4117 else
4118 res = xmlHashAddEntry2(triage,
4119 BAD_CAST "#any", (*tmp)->ns,
4120 (void *) cur);
4121 if (res != 0)
4122 is_triable = -1;
4123 } else {
4124 is_triable = -1;
4125 }
4126 tmp++;
4127 }
4128 }
4129 i++;
4130 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004131 }
4132
Daniel Veillard4c004142003-10-07 11:33:24 +00004133 for (i = 0; i < nbchild; i++) {
4134 if (list[i] == NULL)
4135 continue;
4136 for (j = 0; j < i; j++) {
4137 if (list[j] == NULL)
4138 continue;
4139 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4140 if (ret == 0) {
4141 is_indeterminist = 1;
4142 }
4143 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004144 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004145 for (i = 0; i < nbchild; i++) {
4146 if (list[i] != NULL)
4147 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004148 }
4149
4150 xmlFree(list);
4151 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004152 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004153 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004154 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004155 def->dflags |= IS_TRIABLE;
4156 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004157 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004158 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004159 }
4160 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004161}
4162
4163/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004164 * xmlRelaxNGCheckGroupAttrs:
4165 * @ctxt: a Relax-NG parser context
4166 * @def: the group definition
4167 *
4168 * Detects violations of rule 7.3
4169 */
4170static void
4171xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004172 xmlRelaxNGDefinePtr def)
4173{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004174 xmlRelaxNGDefinePtr **list;
4175 xmlRelaxNGDefinePtr cur;
4176 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004177
4178 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004179 ((def->type != XML_RELAXNG_GROUP) &&
4180 (def->type != XML_RELAXNG_ELEMENT)))
4181 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004182
Daniel Veillarde063f482003-03-21 16:53:17 +00004183 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004184 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004185
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004186 /*
4187 * Don't run that check in case of error. Infinite recursion
4188 * becomes possible.
4189 */
4190 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004191 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004192
Daniel Veillardfd573f12003-03-16 17:52:32 +00004193 cur = def->attrs;
4194 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004195 nbchild++;
4196 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004197 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004198 cur = def->content;
4199 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004200 nbchild++;
4201 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004202 }
4203
4204 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004205 sizeof(xmlRelaxNGDefinePtr
4206 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004207 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004208 xmlRngPErrMemory(ctxt, "building group\n");
4209 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004210 }
4211 i = 0;
4212 cur = def->attrs;
4213 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004214 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4215 i++;
4216 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004217 }
4218 cur = def->content;
4219 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004220 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4221 i++;
4222 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004223 }
4224
Daniel Veillard4c004142003-10-07 11:33:24 +00004225 for (i = 0; i < nbchild; i++) {
4226 if (list[i] == NULL)
4227 continue;
4228 for (j = 0; j < i; j++) {
4229 if (list[j] == NULL)
4230 continue;
4231 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4232 if (ret == 0) {
4233 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4234 "Attributes conflicts in group\n", NULL, NULL);
4235 }
4236 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004237 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004238 for (i = 0; i < nbchild; i++) {
4239 if (list[i] != NULL)
4240 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004241 }
4242
4243 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004244 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004245}
4246
4247/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004248 * xmlRelaxNGComputeInterleaves:
4249 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004250 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004251 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004252 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004253 * A lot of work for preprocessing interleave definitions
4254 * is potentially needed to get a decent execution speed at runtime
4255 * - trying to get a total order on the element nodes generated
4256 * by the interleaves, order the list of interleave definitions
4257 * following that order.
4258 * - if <text/> is used to handle mixed content, it is better to
4259 * flag this in the define and simplify the runtime checking
4260 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004261 */
4262static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004263xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004264 xmlRelaxNGParserCtxtPtr ctxt,
4265 xmlChar * name ATTRIBUTE_UNUSED)
4266{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004267 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004268
Daniel Veillardfd573f12003-03-16 17:52:32 +00004269 xmlRelaxNGPartitionPtr partitions = NULL;
4270 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4271 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004272 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004273 int nbgroups = 0;
4274 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004275 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004276 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004277
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004278 /*
4279 * Don't run that check in case of error. Infinite recursion
4280 * becomes possible.
4281 */
4282 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004283 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004284
Daniel Veillardfd573f12003-03-16 17:52:32 +00004285#ifdef DEBUG_INTERLEAVE
4286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004287 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004288#endif
4289 cur = def->content;
4290 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004291 nbchild++;
4292 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004293 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004294
Daniel Veillardfd573f12003-03-16 17:52:32 +00004295#ifdef DEBUG_INTERLEAVE
4296 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4297#endif
4298 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004299 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004300 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004301 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004302 cur = def->content;
4303 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004304 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4305 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4306 if (groups[nbgroups] == NULL)
4307 goto error;
4308 if (cur->type == XML_RELAXNG_TEXT)
4309 is_mixed++;
4310 groups[nbgroups]->rule = cur;
4311 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4312 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4313 nbgroups++;
4314 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004315 }
4316#ifdef DEBUG_INTERLEAVE
4317 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4318#endif
4319
4320 /*
4321 * Let's check that all rules makes a partitions according to 7.4
4322 */
4323 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004324 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004325 if (partitions == NULL)
4326 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004327 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004328 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004329 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004330 for (i = 0; i < nbgroups; i++) {
4331 group = groups[i];
4332 for (j = i + 1; j < nbgroups; j++) {
4333 if (groups[j] == NULL)
4334 continue;
4335
4336 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4337 groups[j]->defs);
4338 if (ret == 0) {
4339 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4340 "Element or text conflicts in interleave\n",
4341 NULL, NULL);
4342 }
4343 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4344 groups[j]->attrs);
4345 if (ret == 0) {
4346 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4347 "Attributes conflicts in interleave\n", NULL,
4348 NULL);
4349 }
4350 }
4351 tmp = group->defs;
4352 if ((tmp != NULL) && (*tmp != NULL)) {
4353 while (*tmp != NULL) {
4354 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4355 res = xmlHashAddEntry2(partitions->triage,
4356 BAD_CAST "#text", NULL,
4357 (void *) (long) (i + 1));
4358 if (res != 0)
4359 is_determinist = -1;
4360 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4361 ((*tmp)->name != NULL)) {
4362 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4363 res = xmlHashAddEntry2(partitions->triage,
4364 (*tmp)->name, NULL,
4365 (void *) (long) (i + 1));
4366 else
4367 res = xmlHashAddEntry2(partitions->triage,
4368 (*tmp)->name, (*tmp)->ns,
4369 (void *) (long) (i + 1));
4370 if (res != 0)
4371 is_determinist = -1;
4372 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4373 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4374 res = xmlHashAddEntry2(partitions->triage,
4375 BAD_CAST "#any", NULL,
4376 (void *) (long) (i + 1));
4377 else
4378 res = xmlHashAddEntry2(partitions->triage,
4379 BAD_CAST "#any", (*tmp)->ns,
4380 (void *) (long) (i + 1));
4381 if ((*tmp)->nameClass != NULL)
4382 is_determinist = 2;
4383 if (res != 0)
4384 is_determinist = -1;
4385 } else {
4386 is_determinist = -1;
4387 }
4388 tmp++;
4389 }
4390 } else {
4391 is_determinist = 0;
4392 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004393 }
4394 partitions->groups = groups;
4395
4396 /*
4397 * and save the partition list back in the def
4398 */
4399 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004400 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004401 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004402 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004403 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004404 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004405 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004406 return;
4407
Daniel Veillard4c004142003-10-07 11:33:24 +00004408 error:
4409 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004410 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004411 for (i = 0; i < nbgroups; i++)
4412 if (groups[i] != NULL) {
4413 if (groups[i]->defs != NULL)
4414 xmlFree(groups[i]->defs);
4415 xmlFree(groups[i]);
4416 }
4417 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004418 }
4419 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004420}
4421
4422/**
4423 * xmlRelaxNGParseInterleave:
4424 * @ctxt: a Relax-NG parser context
4425 * @node: the data node.
4426 *
4427 * parse the content of a RelaxNG interleave node.
4428 *
4429 * Returns the definition pointer or NULL in case of error
4430 */
4431static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004432xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4433{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004434 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004435 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004436 xmlNodePtr child;
4437
Daniel Veillardfd573f12003-03-16 17:52:32 +00004438 def = xmlRelaxNGNewDefine(ctxt, node);
4439 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004440 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004441 }
4442 def->type = XML_RELAXNG_INTERLEAVE;
4443
4444 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004445 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004446 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004447 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004448 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004449 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004450
Daniel Veillard4c004142003-10-07 11:33:24 +00004451 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4452 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4453 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4454 "Failed to add %s to hash table\n",
4455 (const xmlChar *) name, NULL);
4456 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004457 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004458 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004459 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004460 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4461 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004462 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004463 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004464 if (IS_RELAXNG(child, "element")) {
4465 cur = xmlRelaxNGParseElement(ctxt, child);
4466 } else {
4467 cur = xmlRelaxNGParsePattern(ctxt, child);
4468 }
4469 if (cur != NULL) {
4470 cur->parent = def;
4471 if (last == NULL) {
4472 def->content = last = cur;
4473 } else {
4474 last->next = cur;
4475 last = cur;
4476 }
4477 }
4478 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004479 }
4480
Daniel Veillard4c004142003-10-07 11:33:24 +00004481 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004482}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004483
4484/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004485 * xmlRelaxNGParseInclude:
4486 * @ctxt: a Relax-NG parser context
4487 * @node: the include node
4488 *
4489 * Integrate the content of an include node in the current grammar
4490 *
4491 * Returns 0 in case of success or -1 in case of error
4492 */
4493static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004494xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4495{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004496 xmlRelaxNGIncludePtr incl;
4497 xmlNodePtr root;
4498 int ret = 0, tmp;
4499
Daniel Veillard807daf82004-02-22 22:13:27 +00004500 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004501 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004502 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4503 "Include node has no data\n", NULL, NULL);
4504 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004505 }
4506 root = xmlDocGetRootElement(incl->doc);
4507 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004508 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4509 NULL, NULL);
4510 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004511 }
4512 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004513 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4514 "Include document root is not a grammar\n", NULL, NULL);
4515 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004516 }
4517
4518 /*
4519 * Merge the definition from both the include and the internal list
4520 */
4521 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004522 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4523 if (tmp != 0)
4524 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004525 }
4526 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004527 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4528 if (tmp != 0)
4529 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004530 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004531 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004532}
4533
4534/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004535 * xmlRelaxNGParseDefine:
4536 * @ctxt: a Relax-NG parser context
4537 * @node: the define node
4538 *
4539 * parse the content of a RelaxNG define element node.
4540 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004541 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004542 */
4543static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004544xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4545{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004546 xmlChar *name;
4547 int ret = 0, tmp;
4548 xmlRelaxNGDefinePtr def;
4549 const xmlChar *olddefine;
4550
4551 name = xmlGetProp(node, BAD_CAST "name");
4552 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004553 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4554 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004555 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004556 xmlRelaxNGNormExtSpace(name);
4557 if (xmlValidateNCName(name, 0)) {
4558 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4559 "define name '%s' is not an NCName\n", name, NULL);
4560 }
4561 def = xmlRelaxNGNewDefine(ctxt, node);
4562 if (def == NULL) {
4563 xmlFree(name);
4564 return (-1);
4565 }
4566 def->type = XML_RELAXNG_DEF;
4567 def->name = name;
4568 if (node->children == NULL) {
4569 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4570 "define has no children\n", NULL, NULL);
4571 } else {
4572 olddefine = ctxt->define;
4573 ctxt->define = name;
4574 def->content =
4575 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4576 ctxt->define = olddefine;
4577 }
4578 if (ctxt->grammar->defs == NULL)
4579 ctxt->grammar->defs = xmlHashCreate(10);
4580 if (ctxt->grammar->defs == NULL) {
4581 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4582 "Could not create definition hash\n", NULL, NULL);
4583 ret = -1;
4584 } else {
4585 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4586 if (tmp < 0) {
4587 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004588
Daniel Veillard4c004142003-10-07 11:33:24 +00004589 prev = xmlHashLookup(ctxt->grammar->defs, name);
4590 if (prev == NULL) {
4591 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4592 "Internal error on define aggregation of %s\n",
4593 name, NULL);
4594 ret = -1;
4595 } else {
4596 while (prev->nextHash != NULL)
4597 prev = prev->nextHash;
4598 prev->nextHash = def;
4599 }
4600 }
4601 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004602 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004603 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004604}
4605
4606/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004607 * xmlRelaxNGProcessExternalRef:
4608 * @ctxt: the parser context
4609 * @node: the externlRef node
4610 *
4611 * Process and compile an externlRef node
4612 *
4613 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4614 */
4615static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004616xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4617{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004618 xmlRelaxNGDocumentPtr docu;
4619 xmlNodePtr root, tmp;
4620 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004621 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004622 xmlRelaxNGDefinePtr def;
4623
Daniel Veillard807daf82004-02-22 22:13:27 +00004624 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004625 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004626 def = xmlRelaxNGNewDefine(ctxt, node);
4627 if (def == NULL)
4628 return (NULL);
4629 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004630
Daniel Veillard4c004142003-10-07 11:33:24 +00004631 if (docu->content == NULL) {
4632 /*
4633 * Then do the parsing for good
4634 */
4635 root = xmlDocGetRootElement(docu->doc);
4636 if (root == NULL) {
4637 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4638 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4639 NULL);
4640 return (NULL);
4641 }
4642 /*
4643 * ns transmission rules
4644 */
4645 ns = xmlGetProp(root, BAD_CAST "ns");
4646 if (ns == NULL) {
4647 tmp = node;
4648 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4649 ns = xmlGetProp(tmp, BAD_CAST "ns");
4650 if (ns != NULL) {
4651 break;
4652 }
4653 tmp = tmp->parent;
4654 }
4655 if (ns != NULL) {
4656 xmlSetProp(root, BAD_CAST "ns", ns);
4657 newNs = 1;
4658 xmlFree(ns);
4659 }
4660 } else {
4661 xmlFree(ns);
4662 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004663
Daniel Veillard4c004142003-10-07 11:33:24 +00004664 /*
4665 * Parsing to get a precompiled schemas.
4666 */
4667 oldflags = ctxt->flags;
4668 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4669 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4670 ctxt->flags = oldflags;
4671 if ((docu->schema != NULL) &&
4672 (docu->schema->topgrammar != NULL)) {
4673 docu->content = docu->schema->topgrammar->start;
4674 }
4675
4676 /*
4677 * the externalRef may be reused in a different ns context
4678 */
4679 if (newNs == 1) {
4680 xmlUnsetProp(root, BAD_CAST "ns");
4681 }
4682 }
4683 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004684 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004685 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004686 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004687 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004688}
4689
4690/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004691 * xmlRelaxNGParsePattern:
4692 * @ctxt: a Relax-NG parser context
4693 * @node: the pattern node.
4694 *
4695 * parse the content of a RelaxNG pattern node.
4696 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004697 * Returns the definition pointer or NULL in case of error or if no
4698 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004699 */
4700static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004701xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4702{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004703 xmlRelaxNGDefinePtr def = NULL;
4704
Daniel Veillardd2298792003-02-14 16:54:11 +00004705 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004706 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004707 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004708 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004709 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004710 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004711 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004712 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004713 def = xmlRelaxNGNewDefine(ctxt, node);
4714 if (def == NULL)
4715 return (NULL);
4716 def->type = XML_RELAXNG_EMPTY;
4717 if (node->children != NULL) {
4718 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4719 "empty: had a child node\n", NULL, NULL);
4720 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004721 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004722 def = xmlRelaxNGNewDefine(ctxt, node);
4723 if (def == NULL)
4724 return (NULL);
4725 def->type = XML_RELAXNG_TEXT;
4726 if (node->children != NULL) {
4727 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4728 "text: had a child node\n", NULL, NULL);
4729 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004730 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004731 def = xmlRelaxNGNewDefine(ctxt, node);
4732 if (def == NULL)
4733 return (NULL);
4734 def->type = XML_RELAXNG_ZEROORMORE;
4735 if (node->children == NULL) {
4736 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4737 "Element %s is empty\n", node->name, NULL);
4738 } else {
4739 def->content =
4740 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4741 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004742 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004743 def = xmlRelaxNGNewDefine(ctxt, node);
4744 if (def == NULL)
4745 return (NULL);
4746 def->type = XML_RELAXNG_ONEORMORE;
4747 if (node->children == NULL) {
4748 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4749 "Element %s is empty\n", node->name, NULL);
4750 } else {
4751 def->content =
4752 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4753 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004754 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004755 def = xmlRelaxNGNewDefine(ctxt, node);
4756 if (def == NULL)
4757 return (NULL);
4758 def->type = XML_RELAXNG_OPTIONAL;
4759 if (node->children == NULL) {
4760 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4761 "Element %s is empty\n", node->name, NULL);
4762 } else {
4763 def->content =
4764 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4765 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004766 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004767 def = xmlRelaxNGNewDefine(ctxt, node);
4768 if (def == NULL)
4769 return (NULL);
4770 def->type = XML_RELAXNG_CHOICE;
4771 if (node->children == NULL) {
4772 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4773 "Element %s is empty\n", node->name, NULL);
4774 } else {
4775 def->content =
4776 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4777 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004778 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004779 def = xmlRelaxNGNewDefine(ctxt, node);
4780 if (def == NULL)
4781 return (NULL);
4782 def->type = XML_RELAXNG_GROUP;
4783 if (node->children == NULL) {
4784 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4785 "Element %s is empty\n", node->name, NULL);
4786 } else {
4787 def->content =
4788 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4789 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004790 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004791 def = xmlRelaxNGNewDefine(ctxt, node);
4792 if (def == NULL)
4793 return (NULL);
4794 def->type = XML_RELAXNG_REF;
4795 def->name = xmlGetProp(node, BAD_CAST "name");
4796 if (def->name == NULL) {
4797 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4798 NULL, NULL);
4799 } else {
4800 xmlRelaxNGNormExtSpace(def->name);
4801 if (xmlValidateNCName(def->name, 0)) {
4802 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4803 "ref name '%s' is not an NCName\n", def->name,
4804 NULL);
4805 }
4806 }
4807 if (node->children != NULL) {
4808 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4809 NULL, NULL);
4810 }
4811 if (ctxt->grammar->refs == NULL)
4812 ctxt->grammar->refs = xmlHashCreate(10);
4813 if (ctxt->grammar->refs == NULL) {
4814 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4815 "Could not create references hash\n", NULL, NULL);
4816 def = NULL;
4817 } else {
4818 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004819
Daniel Veillard4c004142003-10-07 11:33:24 +00004820 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4821 if (tmp < 0) {
4822 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004823
Daniel Veillard4c004142003-10-07 11:33:24 +00004824 prev = (xmlRelaxNGDefinePtr)
4825 xmlHashLookup(ctxt->grammar->refs, def->name);
4826 if (prev == NULL) {
4827 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004828 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4829 "Error refs definitions '%s'\n",
4830 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004831 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004832 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4833 "Error refs definitions\n",
4834 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004835 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004836 def = NULL;
4837 } else {
4838 def->nextHash = prev->nextHash;
4839 prev->nextHash = def;
4840 }
4841 }
4842 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004843 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004844 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004845 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004846 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004847 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004848 def = xmlRelaxNGNewDefine(ctxt, node);
4849 if (def == NULL)
4850 return (NULL);
4851 def->type = XML_RELAXNG_LIST;
4852 if (node->children == NULL) {
4853 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4854 "Element %s is empty\n", node->name, NULL);
4855 } else {
4856 def->content =
4857 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4858 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004859 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004860 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004861 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004862 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004863 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004864 def = xmlRelaxNGNewDefine(ctxt, node);
4865 if (def == NULL)
4866 return (NULL);
4867 def->type = XML_RELAXNG_NOT_ALLOWED;
4868 if (node->children != NULL) {
4869 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4870 "xmlRelaxNGParse: notAllowed element is not empty\n",
4871 NULL, NULL);
4872 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004873 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004874 xmlRelaxNGGrammarPtr grammar, old;
4875 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004876
Daniel Veillardc482e262003-02-26 14:48:48 +00004877#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004878 xmlGenericError(xmlGenericErrorContext,
4879 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004880#endif
4881
Daniel Veillard4c004142003-10-07 11:33:24 +00004882 oldparent = ctxt->parentgrammar;
4883 old = ctxt->grammar;
4884 ctxt->parentgrammar = old;
4885 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4886 if (old != NULL) {
4887 ctxt->grammar = old;
4888 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004889#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004890 if (grammar != NULL) {
4891 grammar->next = old->next;
4892 old->next = grammar;
4893 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004894#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004895 }
4896 if (grammar != NULL)
4897 def = grammar->start;
4898 else
4899 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004900 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004901 if (ctxt->parentgrammar == NULL) {
4902 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4903 "Use of parentRef without a parent grammar\n", NULL,
4904 NULL);
4905 return (NULL);
4906 }
4907 def = xmlRelaxNGNewDefine(ctxt, node);
4908 if (def == NULL)
4909 return (NULL);
4910 def->type = XML_RELAXNG_PARENTREF;
4911 def->name = xmlGetProp(node, BAD_CAST "name");
4912 if (def->name == NULL) {
4913 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4914 "parentRef has no name\n", NULL, NULL);
4915 } else {
4916 xmlRelaxNGNormExtSpace(def->name);
4917 if (xmlValidateNCName(def->name, 0)) {
4918 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4919 "parentRef name '%s' is not an NCName\n",
4920 def->name, NULL);
4921 }
4922 }
4923 if (node->children != NULL) {
4924 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4925 "parentRef is not empty\n", NULL, NULL);
4926 }
4927 if (ctxt->parentgrammar->refs == NULL)
4928 ctxt->parentgrammar->refs = xmlHashCreate(10);
4929 if (ctxt->parentgrammar->refs == NULL) {
4930 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4931 "Could not create references hash\n", NULL, NULL);
4932 def = NULL;
4933 } else if (def->name != NULL) {
4934 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004935
Daniel Veillard4c004142003-10-07 11:33:24 +00004936 tmp =
4937 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4938 if (tmp < 0) {
4939 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004940
Daniel Veillard4c004142003-10-07 11:33:24 +00004941 prev = (xmlRelaxNGDefinePtr)
4942 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4943 if (prev == NULL) {
4944 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4945 "Internal error parentRef definitions '%s'\n",
4946 def->name, NULL);
4947 def = NULL;
4948 } else {
4949 def->nextHash = prev->nextHash;
4950 prev->nextHash = def;
4951 }
4952 }
4953 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004954 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004955 if (node->children == NULL) {
4956 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4957 NULL, NULL);
4958 def = NULL;
4959 } else {
4960 def = xmlRelaxNGParseInterleave(ctxt, node);
4961 if (def != NULL) {
4962 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004963
Daniel Veillard4c004142003-10-07 11:33:24 +00004964 if ((def->content != NULL) && (def->content->next != NULL)) {
4965 tmp = xmlRelaxNGNewDefine(ctxt, node);
4966 if (tmp != NULL) {
4967 tmp->type = XML_RELAXNG_GROUP;
4968 tmp->content = def->content;
4969 def->content = tmp;
4970 }
4971 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004972
Daniel Veillard4c004142003-10-07 11:33:24 +00004973 tmp = xmlRelaxNGNewDefine(ctxt, node);
4974 if (tmp == NULL)
4975 return (def);
4976 tmp->type = XML_RELAXNG_TEXT;
4977 tmp->next = def->content;
4978 def->content = tmp;
4979 }
4980 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004981 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004982 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4983 "Unexpected node %s is not a pattern\n", node->name,
4984 NULL);
4985 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004986 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004987 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004988}
4989
4990/**
4991 * xmlRelaxNGParseAttribute:
4992 * @ctxt: a Relax-NG parser context
4993 * @node: the element node
4994 *
4995 * parse the content of a RelaxNG attribute node.
4996 *
4997 * Returns the definition pointer or NULL in case of error.
4998 */
4999static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005000xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5001{
Daniel Veillardd2298792003-02-14 16:54:11 +00005002 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005003 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005004 int old_flags;
5005
Daniel Veillardfd573f12003-03-16 17:52:32 +00005006 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005007 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005008 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005009 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005010 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005011 child = node->children;
5012 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005013 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5014 "xmlRelaxNGParseattribute: attribute has no children\n",
5015 NULL, NULL);
5016 return (ret);
5017 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005018 old_flags = ctxt->flags;
5019 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005020 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5021 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005022 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005023
Daniel Veillardd2298792003-02-14 16:54:11 +00005024 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005025 cur = xmlRelaxNGParsePattern(ctxt, child);
5026 if (cur != NULL) {
5027 switch (cur->type) {
5028 case XML_RELAXNG_EMPTY:
5029 case XML_RELAXNG_NOT_ALLOWED:
5030 case XML_RELAXNG_TEXT:
5031 case XML_RELAXNG_ELEMENT:
5032 case XML_RELAXNG_DATATYPE:
5033 case XML_RELAXNG_VALUE:
5034 case XML_RELAXNG_LIST:
5035 case XML_RELAXNG_REF:
5036 case XML_RELAXNG_PARENTREF:
5037 case XML_RELAXNG_EXTERNALREF:
5038 case XML_RELAXNG_DEF:
5039 case XML_RELAXNG_ONEORMORE:
5040 case XML_RELAXNG_ZEROORMORE:
5041 case XML_RELAXNG_OPTIONAL:
5042 case XML_RELAXNG_CHOICE:
5043 case XML_RELAXNG_GROUP:
5044 case XML_RELAXNG_INTERLEAVE:
5045 case XML_RELAXNG_ATTRIBUTE:
5046 ret->content = cur;
5047 cur->parent = ret;
5048 break;
5049 case XML_RELAXNG_START:
5050 case XML_RELAXNG_PARAM:
5051 case XML_RELAXNG_EXCEPT:
5052 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5053 "attribute has invalid content\n", NULL,
5054 NULL);
5055 break;
5056 case XML_RELAXNG_NOOP:
5057 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5058 "RNG Internal error, noop found in attribute\n",
5059 NULL, NULL);
5060 break;
5061 }
5062 }
5063 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005064 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005065 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005066 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5067 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005068 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005069 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005070 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005071}
5072
5073/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005074 * xmlRelaxNGParseExceptNameClass:
5075 * @ctxt: a Relax-NG parser context
5076 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005077 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005078 *
5079 * parse the content of a RelaxNG nameClass node.
5080 *
5081 * Returns the definition pointer or NULL in case of error.
5082 */
5083static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005084xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005085 xmlNodePtr node, int attr)
5086{
Daniel Veillard144fae12003-02-03 13:17:57 +00005087 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5088 xmlNodePtr child;
5089
Daniel Veillardd2298792003-02-14 16:54:11 +00005090 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005091 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5092 "Expecting an except node\n", NULL, NULL);
5093 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005094 }
5095 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005096 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5097 "exceptNameClass allows only a single except node\n",
5098 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005099 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005100 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005101 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5102 NULL, NULL);
5103 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005104 }
5105
Daniel Veillardfd573f12003-03-16 17:52:32 +00005106 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005107 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005108 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005109 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005110 child = node->children;
5111 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005112 cur = xmlRelaxNGNewDefine(ctxt, child);
5113 if (cur == NULL)
5114 break;
5115 if (attr)
5116 cur->type = XML_RELAXNG_ATTRIBUTE;
5117 else
5118 cur->type = XML_RELAXNG_ELEMENT;
5119
Daniel Veillard419a7682003-02-03 23:22:49 +00005120 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005121 if (last == NULL) {
5122 ret->content = cur;
5123 } else {
5124 last->next = cur;
5125 }
5126 last = cur;
5127 }
5128 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005129 }
5130
Daniel Veillard4c004142003-10-07 11:33:24 +00005131 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005132}
5133
5134/**
5135 * xmlRelaxNGParseNameClass:
5136 * @ctxt: a Relax-NG parser context
5137 * @node: the nameClass node
5138 * @def: the current definition
5139 *
5140 * parse the content of a RelaxNG nameClass node.
5141 *
5142 * Returns the definition pointer or NULL in case of error.
5143 */
5144static xmlRelaxNGDefinePtr
5145xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005146 xmlRelaxNGDefinePtr def)
5147{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005148 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005149 xmlChar *val;
5150
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005151 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005152 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005153 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005154 if ((def->type != XML_RELAXNG_ELEMENT) &&
5155 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5156 ret = xmlRelaxNGNewDefine(ctxt, node);
5157 if (ret == NULL)
5158 return (NULL);
5159 ret->parent = def;
5160 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5161 ret->type = XML_RELAXNG_ATTRIBUTE;
5162 else
5163 ret->type = XML_RELAXNG_ELEMENT;
5164 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005165 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005166 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005167 val = xmlNodeGetContent(node);
5168 xmlRelaxNGNormExtSpace(val);
5169 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005170 if (node->parent != NULL)
5171 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5172 "Element %s name '%s' is not an NCName\n",
5173 node->parent->name, val);
5174 else
5175 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5176 "name '%s' is not an NCName\n",
5177 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005178 }
5179 ret->name = val;
5180 val = xmlGetProp(node, BAD_CAST "ns");
5181 ret->ns = val;
5182 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5183 (val != NULL) &&
5184 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005185 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005186 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005187 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005188 }
5189 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5190 (val != NULL) &&
5191 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005192 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5193 "Attribute with QName 'xmlns' is not allowed\n",
5194 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005195 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005196 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005197 ret->name = NULL;
5198 ret->ns = NULL;
5199 if (node->children != NULL) {
5200 ret->nameClass =
5201 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5202 (def->type ==
5203 XML_RELAXNG_ATTRIBUTE));
5204 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005205 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005206 ret->name = NULL;
5207 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5208 if (ret->ns == NULL) {
5209 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5210 "nsName has no ns attribute\n", NULL, NULL);
5211 }
5212 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5213 (ret->ns != NULL) &&
5214 (xmlStrEqual
5215 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5216 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5217 "Attribute with namespace '%s' is not allowed\n",
5218 ret->ns, NULL);
5219 }
5220 if (node->children != NULL) {
5221 ret->nameClass =
5222 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5223 (def->type ==
5224 XML_RELAXNG_ATTRIBUTE));
5225 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005226 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005227 xmlNodePtr child;
5228 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005229
Daniel Veillard4c004142003-10-07 11:33:24 +00005230 ret = xmlRelaxNGNewDefine(ctxt, node);
5231 if (ret == NULL)
5232 return (NULL);
5233 ret->parent = def;
5234 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005235
Daniel Veillard4c004142003-10-07 11:33:24 +00005236 if (node->children == NULL) {
5237 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5238 "Element choice is empty\n", NULL, NULL);
5239 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005240
Daniel Veillard4c004142003-10-07 11:33:24 +00005241 child = node->children;
5242 while (child != NULL) {
5243 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5244 if (tmp != NULL) {
5245 if (last == NULL) {
5246 last = ret->nameClass = tmp;
5247 } else {
5248 last->next = tmp;
5249 last = tmp;
5250 }
5251 }
5252 child = child->next;
5253 }
5254 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005255 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005256 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5257 "expecting name, anyName, nsName or choice : got %s\n",
5258 node->name, NULL);
5259 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005260 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005261 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005262 if (def->nameClass == NULL) {
5263 def->nameClass = ret;
5264 } else {
5265 tmp = def->nameClass;
5266 while (tmp->next != NULL) {
5267 tmp = tmp->next;
5268 }
5269 tmp->next = ret;
5270 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005271 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005272 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005273}
5274
5275/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005276 * xmlRelaxNGParseElement:
5277 * @ctxt: a Relax-NG parser context
5278 * @node: the element node
5279 *
5280 * parse the content of a RelaxNG element node.
5281 *
5282 * Returns the definition pointer or NULL in case of error.
5283 */
5284static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005285xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5286{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005287 xmlRelaxNGDefinePtr ret, cur, last;
5288 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005289 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005290
Daniel Veillardfd573f12003-03-16 17:52:32 +00005291 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005292 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005293 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005294 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005295 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005296 child = node->children;
5297 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005298 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5299 "xmlRelaxNGParseElement: element has no children\n",
5300 NULL, NULL);
5301 return (ret);
5302 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005303 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5304 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005305 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005306
Daniel Veillard6eadf632003-01-23 18:29:16 +00005307 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005308 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5309 "xmlRelaxNGParseElement: element has no content\n",
5310 NULL, NULL);
5311 return (ret);
5312 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005313 olddefine = ctxt->define;
5314 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005315 last = NULL;
5316 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005317 cur = xmlRelaxNGParsePattern(ctxt, child);
5318 if (cur != NULL) {
5319 cur->parent = ret;
5320 switch (cur->type) {
5321 case XML_RELAXNG_EMPTY:
5322 case XML_RELAXNG_NOT_ALLOWED:
5323 case XML_RELAXNG_TEXT:
5324 case XML_RELAXNG_ELEMENT:
5325 case XML_RELAXNG_DATATYPE:
5326 case XML_RELAXNG_VALUE:
5327 case XML_RELAXNG_LIST:
5328 case XML_RELAXNG_REF:
5329 case XML_RELAXNG_PARENTREF:
5330 case XML_RELAXNG_EXTERNALREF:
5331 case XML_RELAXNG_DEF:
5332 case XML_RELAXNG_ZEROORMORE:
5333 case XML_RELAXNG_ONEORMORE:
5334 case XML_RELAXNG_OPTIONAL:
5335 case XML_RELAXNG_CHOICE:
5336 case XML_RELAXNG_GROUP:
5337 case XML_RELAXNG_INTERLEAVE:
5338 if (last == NULL) {
5339 ret->content = last = cur;
5340 } else {
5341 if ((last->type == XML_RELAXNG_ELEMENT) &&
5342 (ret->content == last)) {
5343 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5344 if (ret->content != NULL) {
5345 ret->content->type = XML_RELAXNG_GROUP;
5346 ret->content->content = last;
5347 } else {
5348 ret->content = last;
5349 }
5350 }
5351 last->next = cur;
5352 last = cur;
5353 }
5354 break;
5355 case XML_RELAXNG_ATTRIBUTE:
5356 cur->next = ret->attrs;
5357 ret->attrs = cur;
5358 break;
5359 case XML_RELAXNG_START:
5360 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5361 "RNG Internal error, start found in element\n",
5362 NULL, NULL);
5363 break;
5364 case XML_RELAXNG_PARAM:
5365 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5366 "RNG Internal error, param found in element\n",
5367 NULL, NULL);
5368 break;
5369 case XML_RELAXNG_EXCEPT:
5370 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5371 "RNG Internal error, except found in element\n",
5372 NULL, NULL);
5373 break;
5374 case XML_RELAXNG_NOOP:
5375 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5376 "RNG Internal error, noop found in element\n",
5377 NULL, NULL);
5378 break;
5379 }
5380 }
5381 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005382 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005383 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005384 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005385}
5386
5387/**
5388 * xmlRelaxNGParsePatterns:
5389 * @ctxt: a Relax-NG parser context
5390 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005391 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005392 *
5393 * parse the content of a RelaxNG start node.
5394 *
5395 * Returns the definition pointer or NULL in case of error.
5396 */
5397static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005398xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005399 int group)
5400{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005401 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005402
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005403 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005404 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005405 if (IS_RELAXNG(nodes, "element")) {
5406 cur = xmlRelaxNGParseElement(ctxt, nodes);
5407 if (def == NULL) {
5408 def = last = cur;
5409 } else {
5410 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5411 (def == last)) {
5412 def = xmlRelaxNGNewDefine(ctxt, nodes);
5413 def->type = XML_RELAXNG_GROUP;
5414 def->content = last;
5415 }
5416 last->next = cur;
5417 last = cur;
5418 }
5419 cur->parent = parent;
5420 } else {
5421 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5422 if (cur != NULL) {
5423 if (def == NULL) {
5424 def = last = cur;
5425 } else {
5426 last->next = cur;
5427 last = cur;
5428 }
5429 }
5430 }
5431 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005432 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005433 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005434}
5435
5436/**
5437 * xmlRelaxNGParseStart:
5438 * @ctxt: a Relax-NG parser context
5439 * @nodes: start children nodes
5440 *
5441 * parse the content of a RelaxNG start node.
5442 *
5443 * Returns 0 in case of success, -1 in case of error
5444 */
5445static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005446xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5447{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005448 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005449 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005450
Daniel Veillardd2298792003-02-14 16:54:11 +00005451 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005452 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5453 NULL, NULL);
5454 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005455 }
5456 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005457 def = xmlRelaxNGNewDefine(ctxt, nodes);
5458 if (def == NULL)
5459 return (-1);
5460 def->type = XML_RELAXNG_EMPTY;
5461 if (nodes->children != NULL) {
5462 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5463 "element empty is not empty\n", NULL, NULL);
5464 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005465 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005466 def = xmlRelaxNGNewDefine(ctxt, nodes);
5467 if (def == NULL)
5468 return (-1);
5469 def->type = XML_RELAXNG_NOT_ALLOWED;
5470 if (nodes->children != NULL) {
5471 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5472 "element notAllowed is not empty\n", NULL, NULL);
5473 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005474 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005475 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005476 }
5477 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005478 last = ctxt->grammar->start;
5479 while (last->next != NULL)
5480 last = last->next;
5481 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005482 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005483 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005484 }
5485 nodes = nodes->next;
5486 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005487 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5488 "start more than one children\n", NULL, NULL);
5489 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005490 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005491 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005492}
5493
5494/**
5495 * xmlRelaxNGParseGrammarContent:
5496 * @ctxt: a Relax-NG parser context
5497 * @nodes: grammar children nodes
5498 *
5499 * parse the content of a RelaxNG grammar node.
5500 *
5501 * Returns 0 in case of success, -1 in case of error
5502 */
5503static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005504xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5505 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005507 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005508
5509 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005510 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5511 "grammar has no children\n", NULL, NULL);
5512 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005513 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005514 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005515 if (IS_RELAXNG(nodes, "start")) {
5516 if (nodes->children == NULL) {
5517 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5518 "start has no children\n", NULL, NULL);
5519 } else {
5520 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5521 if (tmp != 0)
5522 ret = -1;
5523 }
5524 } else if (IS_RELAXNG(nodes, "define")) {
5525 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5526 if (tmp != 0)
5527 ret = -1;
5528 } else if (IS_RELAXNG(nodes, "include")) {
5529 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5530 if (tmp != 0)
5531 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005532 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005533 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5534 "grammar has unexpected child %s\n", nodes->name,
5535 NULL);
5536 ret = -1;
5537 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005538 nodes = nodes->next;
5539 }
5540 return (ret);
5541}
5542
5543/**
5544 * xmlRelaxNGCheckReference:
5545 * @ref: the ref
5546 * @ctxt: a Relax-NG parser context
5547 * @name: the name associated to the defines
5548 *
5549 * Applies the 4.17. combine attribute rule for all the define
5550 * element of a given grammar using the same name.
5551 */
5552static void
5553xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005554 xmlRelaxNGParserCtxtPtr ctxt,
5555 const xmlChar * name)
5556{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005557 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005558 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005559
5560 grammar = ctxt->grammar;
5561 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005562 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5563 "Internal error: no grammar in CheckReference %s\n",
5564 name, NULL);
5565 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005566 }
5567 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005568 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5569 "Internal error: reference has content in CheckReference %s\n",
5570 name, NULL);
5571 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005572 }
5573 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005574 def = xmlHashLookup(grammar->defs, name);
5575 if (def != NULL) {
5576 cur = ref;
5577 while (cur != NULL) {
5578 cur->content = def;
5579 cur = cur->nextHash;
5580 }
5581 } else {
5582 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5583 "Reference %s has no matching definition\n", name,
5584 NULL);
5585 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005586 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005587 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5588 "Reference %s has no matching definition\n", name,
5589 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005590 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005591}
5592
5593/**
5594 * xmlRelaxNGCheckCombine:
5595 * @define: the define(s) list
5596 * @ctxt: a Relax-NG parser context
5597 * @name: the name associated to the defines
5598 *
5599 * Applies the 4.17. combine attribute rule for all the define
5600 * element of a given grammar using the same name.
5601 */
5602static void
5603xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005604 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5605{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005606 xmlChar *combine;
5607 int choiceOrInterleave = -1;
5608 int missing = 0;
5609 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5610
5611 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005612 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005613 cur = define;
5614 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005615 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5616 if (combine != NULL) {
5617 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5618 if (choiceOrInterleave == -1)
5619 choiceOrInterleave = 1;
5620 else if (choiceOrInterleave == 0) {
5621 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5622 "Defines for %s use both 'choice' and 'interleave'\n",
5623 name, NULL);
5624 }
5625 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5626 if (choiceOrInterleave == -1)
5627 choiceOrInterleave = 0;
5628 else if (choiceOrInterleave == 1) {
5629 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5630 "Defines for %s use both 'choice' and 'interleave'\n",
5631 name, NULL);
5632 }
5633 } else {
5634 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5635 "Defines for %s use unknown combine value '%s''\n",
5636 name, combine);
5637 }
5638 xmlFree(combine);
5639 } else {
5640 if (missing == 0)
5641 missing = 1;
5642 else {
5643 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5644 "Some defines for %s needs the combine attribute\n",
5645 name, NULL);
5646 }
5647 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005648
Daniel Veillard4c004142003-10-07 11:33:24 +00005649 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005650 }
5651#ifdef DEBUG
5652 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005653 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5654 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005655#endif
5656 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005657 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005658 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005659 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005660 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005661 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005662 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005663 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005664 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005665 tmp = define;
5666 last = NULL;
5667 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005668 if (tmp->content != NULL) {
5669 if (tmp->content->next != NULL) {
5670 /*
5671 * we need first to create a wrapper.
5672 */
5673 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5674 if (tmp2 == NULL)
5675 break;
5676 tmp2->type = XML_RELAXNG_GROUP;
5677 tmp2->content = tmp->content;
5678 } else {
5679 tmp2 = tmp->content;
5680 }
5681 if (last == NULL) {
5682 cur->content = tmp2;
5683 } else {
5684 last->next = tmp2;
5685 }
5686 last = tmp2;
5687 }
5688 tmp->content = cur;
5689 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005690 }
5691 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005692 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005693 if (ctxt->interleaves == NULL)
5694 ctxt->interleaves = xmlHashCreate(10);
5695 if (ctxt->interleaves == NULL) {
5696 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5697 "Failed to create interleaves hash table\n", NULL,
5698 NULL);
5699 } else {
5700 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005701
Daniel Veillard4c004142003-10-07 11:33:24 +00005702 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5703 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5704 0) {
5705 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5706 "Failed to add %s to hash table\n",
5707 (const xmlChar *) tmpname, NULL);
5708 }
5709 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005710 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005711}
5712
5713/**
5714 * xmlRelaxNGCombineStart:
5715 * @ctxt: a Relax-NG parser context
5716 * @grammar: the grammar
5717 *
5718 * Applies the 4.17. combine rule for all the start
5719 * element of a given grammar.
5720 */
5721static void
5722xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005723 xmlRelaxNGGrammarPtr grammar)
5724{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005725 xmlRelaxNGDefinePtr starts;
5726 xmlChar *combine;
5727 int choiceOrInterleave = -1;
5728 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005729 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005730
Daniel Veillard2df2de22003-02-17 23:34:33 +00005731 starts = grammar->start;
5732 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005733 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005734 cur = starts;
5735 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005736 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5737 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5738 combine = NULL;
5739 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5740 "Internal error: start element not found\n", NULL,
5741 NULL);
5742 } else {
5743 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5744 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005745
Daniel Veillard4c004142003-10-07 11:33:24 +00005746 if (combine != NULL) {
5747 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5748 if (choiceOrInterleave == -1)
5749 choiceOrInterleave = 1;
5750 else if (choiceOrInterleave == 0) {
5751 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5752 "<start> use both 'choice' and 'interleave'\n",
5753 NULL, NULL);
5754 }
5755 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5756 if (choiceOrInterleave == -1)
5757 choiceOrInterleave = 0;
5758 else if (choiceOrInterleave == 1) {
5759 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5760 "<start> use both 'choice' and 'interleave'\n",
5761 NULL, NULL);
5762 }
5763 } else {
5764 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5765 "<start> uses unknown combine value '%s''\n",
5766 combine, NULL);
5767 }
5768 xmlFree(combine);
5769 } else {
5770 if (missing == 0)
5771 missing = 1;
5772 else {
5773 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5774 "Some <start> element miss the combine attribute\n",
5775 NULL, NULL);
5776 }
5777 }
5778
5779 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005780 }
5781#ifdef DEBUG
5782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005783 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5784 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005785#endif
5786 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005787 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005788 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005789 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005790 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005791 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005792 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005793 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005794 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005795 cur->content = grammar->start;
5796 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005797 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005798 if (ctxt->interleaves == NULL)
5799 ctxt->interleaves = xmlHashCreate(10);
5800 if (ctxt->interleaves == NULL) {
5801 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5802 "Failed to create interleaves hash table\n", NULL,
5803 NULL);
5804 } else {
5805 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005806
Daniel Veillard4c004142003-10-07 11:33:24 +00005807 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5808 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5809 0) {
5810 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5811 "Failed to add %s to hash table\n",
5812 (const xmlChar *) tmpname, NULL);
5813 }
5814 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005815 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005816}
5817
5818/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005819 * xmlRelaxNGCheckCycles:
5820 * @ctxt: a Relax-NG parser context
5821 * @nodes: grammar children nodes
5822 * @depth: the counter
5823 *
5824 * Check for cycles.
5825 *
5826 * Returns 0 if check passed, and -1 in case of error
5827 */
5828static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005829xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5830 xmlRelaxNGDefinePtr cur, int depth)
5831{
Daniel Veillardd4310742003-02-18 21:12:46 +00005832 int ret = 0;
5833
5834 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005835 if ((cur->type == XML_RELAXNG_REF) ||
5836 (cur->type == XML_RELAXNG_PARENTREF)) {
5837 if (cur->depth == -1) {
5838 cur->depth = depth;
5839 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5840 cur->depth = -2;
5841 } else if (depth == cur->depth) {
5842 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5843 "Detected a cycle in %s references\n",
5844 cur->name, NULL);
5845 return (-1);
5846 }
5847 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5848 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5849 } else {
5850 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5851 }
5852 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005853 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005854 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005855}
5856
5857/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005858 * xmlRelaxNGTryUnlink:
5859 * @ctxt: a Relax-NG parser context
5860 * @cur: the definition to unlink
5861 * @parent: the parent definition
5862 * @prev: the previous sibling definition
5863 *
5864 * Try to unlink a definition. If not possble make it a NOOP
5865 *
5866 * Returns the new prev definition
5867 */
5868static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005869xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5870 xmlRelaxNGDefinePtr cur,
5871 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5872{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005873 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005874 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005875 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005876 if (parent != NULL) {
5877 if (parent->content == cur)
5878 parent->content = cur->next;
5879 else if (parent->attrs == cur)
5880 parent->attrs = cur->next;
5881 else if (parent->nameClass == cur)
5882 parent->nameClass = cur->next;
5883 } else {
5884 cur->type = XML_RELAXNG_NOOP;
5885 prev = cur;
5886 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005887 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005888 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005889}
5890
5891/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005892 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005893 * @ctxt: a Relax-NG parser context
5894 * @nodes: grammar children nodes
5895 *
5896 * Check for simplification of empty and notAllowed
5897 */
5898static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005899xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5900 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5901{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005902 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005903
Daniel Veillardfd573f12003-03-16 17:52:32 +00005904 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005905 if ((cur->type == XML_RELAXNG_REF) ||
5906 (cur->type == XML_RELAXNG_PARENTREF)) {
5907 if (cur->depth != -3) {
5908 cur->depth = -3;
5909 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5910 }
5911 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5912 cur->parent = parent;
5913 if ((parent != NULL) &&
5914 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5915 (parent->type == XML_RELAXNG_LIST) ||
5916 (parent->type == XML_RELAXNG_GROUP) ||
5917 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5918 (parent->type == XML_RELAXNG_ONEORMORE) ||
5919 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5920 parent->type = XML_RELAXNG_NOT_ALLOWED;
5921 break;
5922 }
5923 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5924 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5925 } else
5926 prev = cur;
5927 } else if (cur->type == XML_RELAXNG_EMPTY) {
5928 cur->parent = parent;
5929 if ((parent != NULL) &&
5930 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5931 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5932 parent->type = XML_RELAXNG_EMPTY;
5933 break;
5934 }
5935 if ((parent != NULL) &&
5936 ((parent->type == XML_RELAXNG_GROUP) ||
5937 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5938 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5939 } else
5940 prev = cur;
5941 } else {
5942 cur->parent = parent;
5943 if (cur->content != NULL)
5944 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5945 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5946 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5947 if (cur->nameClass != NULL)
5948 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5949 /*
5950 * On Elements, try to move attribute only generating rules on
5951 * the attrs rules.
5952 */
5953 if (cur->type == XML_RELAXNG_ELEMENT) {
5954 int attronly;
5955 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005956
Daniel Veillard4c004142003-10-07 11:33:24 +00005957 while (cur->content != NULL) {
5958 attronly =
5959 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5960 if (attronly == 1) {
5961 /*
5962 * migrate cur->content to attrs
5963 */
5964 tmp = cur->content;
5965 cur->content = tmp->next;
5966 tmp->next = cur->attrs;
5967 cur->attrs = tmp;
5968 } else {
5969 /*
5970 * cur->content can generate elements or text
5971 */
5972 break;
5973 }
5974 }
5975 pre = cur->content;
5976 while ((pre != NULL) && (pre->next != NULL)) {
5977 tmp = pre->next;
5978 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5979 if (attronly == 1) {
5980 /*
5981 * migrate tmp to attrs
5982 */
5983 pre->next = tmp->next;
5984 tmp->next = cur->attrs;
5985 cur->attrs = tmp;
5986 } else {
5987 pre = tmp;
5988 }
5989 }
5990 }
5991 /*
5992 * This may result in a simplification
5993 */
5994 if ((cur->type == XML_RELAXNG_GROUP) ||
5995 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5996 if (cur->content == NULL)
5997 cur->type = XML_RELAXNG_EMPTY;
5998 else if (cur->content->next == NULL) {
5999 if ((parent == NULL) && (prev == NULL)) {
6000 cur->type = XML_RELAXNG_NOOP;
6001 } else if (prev == NULL) {
6002 parent->content = cur->content;
6003 cur->content->next = cur->next;
6004 cur = cur->content;
6005 } else {
6006 cur->content->next = cur->next;
6007 prev->next = cur->content;
6008 cur = cur->content;
6009 }
6010 }
6011 }
6012 /*
6013 * the current node may have been transformed back
6014 */
6015 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6016 (cur->content != NULL) &&
6017 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6018 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6019 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6020 if ((parent != NULL) &&
6021 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6022 (parent->type == XML_RELAXNG_LIST) ||
6023 (parent->type == XML_RELAXNG_GROUP) ||
6024 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6025 (parent->type == XML_RELAXNG_ONEORMORE) ||
6026 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6027 parent->type = XML_RELAXNG_NOT_ALLOWED;
6028 break;
6029 }
6030 if ((parent != NULL) &&
6031 (parent->type == XML_RELAXNG_CHOICE)) {
6032 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6033 } else
6034 prev = cur;
6035 } else if (cur->type == XML_RELAXNG_EMPTY) {
6036 if ((parent != NULL) &&
6037 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6038 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6039 parent->type = XML_RELAXNG_EMPTY;
6040 break;
6041 }
6042 if ((parent != NULL) &&
6043 ((parent->type == XML_RELAXNG_GROUP) ||
6044 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6045 (parent->type == XML_RELAXNG_CHOICE))) {
6046 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6047 } else
6048 prev = cur;
6049 } else {
6050 prev = cur;
6051 }
6052 }
6053 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006054 }
6055}
6056
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006057/**
6058 * xmlRelaxNGGroupContentType:
6059 * @ct1: the first content type
6060 * @ct2: the second content type
6061 *
6062 * Try to group 2 content types
6063 *
6064 * Returns the content type
6065 */
6066static xmlRelaxNGContentType
6067xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006068 xmlRelaxNGContentType ct2)
6069{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006070 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006071 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6072 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006073 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006074 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006075 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006076 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006077 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006078 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6079 return (XML_RELAXNG_CONTENT_COMPLEX);
6080 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006081}
6082
6083/**
6084 * xmlRelaxNGMaxContentType:
6085 * @ct1: the first content type
6086 * @ct2: the second content type
6087 *
6088 * Compute the max content-type
6089 *
6090 * Returns the content type
6091 */
6092static xmlRelaxNGContentType
6093xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006094 xmlRelaxNGContentType ct2)
6095{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006096 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006097 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6098 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006099 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006100 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6101 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006102 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006103 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6104 return (XML_RELAXNG_CONTENT_COMPLEX);
6105 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006106}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006107
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006108/**
6109 * xmlRelaxNGCheckRules:
6110 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006111 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006112 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006113 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006114 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006115 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006116 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006117 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006118 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006119static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006120xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6121 xmlRelaxNGDefinePtr cur, int flags,
6122 xmlRelaxNGType ptype)
6123{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006124 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006125 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006126
Daniel Veillardfd573f12003-03-16 17:52:32 +00006127 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006128 ret = XML_RELAXNG_CONTENT_EMPTY;
6129 if ((cur->type == XML_RELAXNG_REF) ||
6130 (cur->type == XML_RELAXNG_PARENTREF)) {
6131 if (flags & XML_RELAXNG_IN_LIST) {
6132 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6133 "Found forbidden pattern list//ref\n", NULL,
6134 NULL);
6135 }
6136 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6137 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6138 "Found forbidden pattern data/except//ref\n",
6139 NULL, NULL);
6140 }
6141 if (cur->depth > -4) {
6142 cur->depth = -4;
6143 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6144 flags, cur->type);
6145 cur->depth = ret - 15;
6146 } else if (cur->depth == -4) {
6147 ret = XML_RELAXNG_CONTENT_COMPLEX;
6148 } else {
6149 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6150 }
6151 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6152 /*
6153 * The 7.3 Attribute derivation rule for groups is plugged there
6154 */
6155 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6156 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6157 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6158 "Found forbidden pattern data/except//element(ref)\n",
6159 NULL, NULL);
6160 }
6161 if (flags & XML_RELAXNG_IN_LIST) {
6162 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6163 "Found forbidden pattern list//element(ref)\n",
6164 NULL, NULL);
6165 }
6166 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6167 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6168 "Found forbidden pattern attribute//element(ref)\n",
6169 NULL, NULL);
6170 }
6171 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6172 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6173 "Found forbidden pattern attribute//element(ref)\n",
6174 NULL, NULL);
6175 }
6176 /*
6177 * reset since in the simple form elements are only child
6178 * of grammar/define
6179 */
6180 nflags = 0;
6181 ret =
6182 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6183 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6184 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6185 "Element %s attributes have a content type error\n",
6186 cur->name, NULL);
6187 }
6188 ret =
6189 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6190 cur->type);
6191 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6192 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6193 "Element %s has a content type error\n",
6194 cur->name, NULL);
6195 } else {
6196 ret = XML_RELAXNG_CONTENT_COMPLEX;
6197 }
6198 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6199 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6200 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6201 "Found forbidden pattern attribute//attribute\n",
6202 NULL, NULL);
6203 }
6204 if (flags & XML_RELAXNG_IN_LIST) {
6205 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6206 "Found forbidden pattern list//attribute\n",
6207 NULL, NULL);
6208 }
6209 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6210 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6211 "Found forbidden pattern oneOrMore//group//attribute\n",
6212 NULL, NULL);
6213 }
6214 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6215 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6216 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6217 NULL, NULL);
6218 }
6219 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6220 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6221 "Found forbidden pattern data/except//attribute\n",
6222 NULL, NULL);
6223 }
6224 if (flags & XML_RELAXNG_IN_START) {
6225 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6226 "Found forbidden pattern start//attribute\n",
6227 NULL, NULL);
6228 }
6229 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6230 && (cur->name == NULL)) {
6231 if (cur->ns == NULL) {
6232 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6233 "Found anyName attribute without oneOrMore ancestor\n",
6234 NULL, NULL);
6235 } else {
6236 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6237 "Found nsName attribute without oneOrMore ancestor\n",
6238 NULL, NULL);
6239 }
6240 }
6241 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6242 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6243 ret = XML_RELAXNG_CONTENT_EMPTY;
6244 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6245 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6246 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6247 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6248 "Found forbidden pattern data/except//oneOrMore\n",
6249 NULL, NULL);
6250 }
6251 if (flags & XML_RELAXNG_IN_START) {
6252 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6253 "Found forbidden pattern start//oneOrMore\n",
6254 NULL, NULL);
6255 }
6256 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6257 ret =
6258 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6259 cur->type);
6260 ret = xmlRelaxNGGroupContentType(ret, ret);
6261 } else if (cur->type == XML_RELAXNG_LIST) {
6262 if (flags & XML_RELAXNG_IN_LIST) {
6263 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6264 "Found forbidden pattern list//list\n", NULL,
6265 NULL);
6266 }
6267 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6268 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6269 "Found forbidden pattern data/except//list\n",
6270 NULL, NULL);
6271 }
6272 if (flags & XML_RELAXNG_IN_START) {
6273 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6274 "Found forbidden pattern start//list\n", NULL,
6275 NULL);
6276 }
6277 nflags = flags | XML_RELAXNG_IN_LIST;
6278 ret =
6279 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6280 cur->type);
6281 } else if (cur->type == XML_RELAXNG_GROUP) {
6282 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6283 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6284 "Found forbidden pattern data/except//group\n",
6285 NULL, NULL);
6286 }
6287 if (flags & XML_RELAXNG_IN_START) {
6288 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6289 "Found forbidden pattern start//group\n", NULL,
6290 NULL);
6291 }
6292 if (flags & XML_RELAXNG_IN_ONEORMORE)
6293 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6294 else
6295 nflags = flags;
6296 ret =
6297 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6298 cur->type);
6299 /*
6300 * The 7.3 Attribute derivation rule for groups is plugged there
6301 */
6302 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6303 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6304 if (flags & XML_RELAXNG_IN_LIST) {
6305 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6306 "Found forbidden pattern list//interleave\n",
6307 NULL, NULL);
6308 }
6309 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6310 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6311 "Found forbidden pattern data/except//interleave\n",
6312 NULL, NULL);
6313 }
6314 if (flags & XML_RELAXNG_IN_START) {
6315 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6316 "Found forbidden pattern start//interleave\n",
6317 NULL, NULL);
6318 }
6319 if (flags & XML_RELAXNG_IN_ONEORMORE)
6320 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6321 else
6322 nflags = flags;
6323 ret =
6324 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6325 cur->type);
6326 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6327 if ((cur->parent != NULL) &&
6328 (cur->parent->type == XML_RELAXNG_DATATYPE))
6329 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6330 else
6331 nflags = flags;
6332 ret =
6333 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6334 cur->type);
6335 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6336 if (flags & XML_RELAXNG_IN_START) {
6337 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6338 "Found forbidden pattern start//data\n", NULL,
6339 NULL);
6340 }
6341 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6342 ret = XML_RELAXNG_CONTENT_SIMPLE;
6343 } else if (cur->type == XML_RELAXNG_VALUE) {
6344 if (flags & XML_RELAXNG_IN_START) {
6345 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6346 "Found forbidden pattern start//value\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_TEXT) {
6352 if (flags & XML_RELAXNG_IN_LIST) {
6353 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6354 "Found forbidden pattern list//text\n", NULL,
6355 NULL);
6356 }
6357 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6358 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6359 "Found forbidden pattern data/except//text\n",
6360 NULL, NULL);
6361 }
6362 if (flags & XML_RELAXNG_IN_START) {
6363 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6364 "Found forbidden pattern start//text\n", NULL,
6365 NULL);
6366 }
6367 ret = XML_RELAXNG_CONTENT_COMPLEX;
6368 } else if (cur->type == XML_RELAXNG_EMPTY) {
6369 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6370 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6371 "Found forbidden pattern data/except//empty\n",
6372 NULL, NULL);
6373 }
6374 if (flags & XML_RELAXNG_IN_START) {
6375 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6376 "Found forbidden pattern start//empty\n", NULL,
6377 NULL);
6378 }
6379 ret = XML_RELAXNG_CONTENT_EMPTY;
6380 } else if (cur->type == XML_RELAXNG_CHOICE) {
6381 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6382 ret =
6383 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6384 } else {
6385 ret =
6386 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6387 }
6388 cur = cur->next;
6389 if (ptype == XML_RELAXNG_GROUP) {
6390 val = xmlRelaxNGGroupContentType(val, ret);
6391 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6392 tmp = xmlRelaxNGGroupContentType(val, ret);
6393 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6394 tmp = xmlRelaxNGMaxContentType(val, ret);
6395 } else if (ptype == XML_RELAXNG_CHOICE) {
6396 val = xmlRelaxNGMaxContentType(val, ret);
6397 } else if (ptype == XML_RELAXNG_LIST) {
6398 val = XML_RELAXNG_CONTENT_SIMPLE;
6399 } else if (ptype == XML_RELAXNG_EXCEPT) {
6400 if (ret == XML_RELAXNG_CONTENT_ERROR)
6401 val = XML_RELAXNG_CONTENT_ERROR;
6402 else
6403 val = XML_RELAXNG_CONTENT_SIMPLE;
6404 } else {
6405 val = xmlRelaxNGGroupContentType(val, ret);
6406 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006407
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006408 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006409 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006410}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006411
6412/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006413 * xmlRelaxNGParseGrammar:
6414 * @ctxt: a Relax-NG parser context
6415 * @nodes: grammar children nodes
6416 *
6417 * parse a Relax-NG <grammar> node
6418 *
6419 * Returns the internal xmlRelaxNGGrammarPtr built or
6420 * NULL in case of error
6421 */
6422static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006423xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6424{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006425 xmlRelaxNGGrammarPtr ret, tmp, old;
6426
Daniel Veillardc482e262003-02-26 14:48:48 +00006427#ifdef DEBUG_GRAMMAR
6428 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6429#endif
6430
Daniel Veillard6eadf632003-01-23 18:29:16 +00006431 ret = xmlRelaxNGNewGrammar(ctxt);
6432 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006433 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006434
6435 /*
6436 * Link the new grammar in the tree
6437 */
6438 ret->parent = ctxt->grammar;
6439 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006440 tmp = ctxt->grammar->children;
6441 if (tmp == NULL) {
6442 ctxt->grammar->children = ret;
6443 } else {
6444 while (tmp->next != NULL)
6445 tmp = tmp->next;
6446 tmp->next = ret;
6447 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006448 }
6449
6450 old = ctxt->grammar;
6451 ctxt->grammar = ret;
6452 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6453 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006454 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006455 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6456 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006457 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006458 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6459 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006460 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006461
6462 /*
6463 * Apply 4.17 mergingd rules to defines and starts
6464 */
6465 xmlRelaxNGCombineStart(ctxt, ret);
6466 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006467 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6468 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469 }
6470
6471 /*
6472 * link together defines and refs in this grammar
6473 */
6474 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006475 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6476 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006477 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006478
Daniel Veillard6eadf632003-01-23 18:29:16 +00006479 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006480 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006481}
6482
6483/**
6484 * xmlRelaxNGParseDocument:
6485 * @ctxt: a Relax-NG parser context
6486 * @node: the root node of the RelaxNG schema
6487 *
6488 * parse a Relax-NG definition resource and build an internal
6489 * xmlRelaxNG struture which can be used to validate instances.
6490 *
6491 * Returns the internal XML RelaxNG structure built or
6492 * NULL in case of error
6493 */
6494static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006495xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6496{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006497 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006498 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006499 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006500
6501 if ((ctxt == NULL) || (node == NULL))
6502 return (NULL);
6503
6504 schema = xmlRelaxNGNewRelaxNG(ctxt);
6505 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006506 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006507
Daniel Veillard276be4a2003-01-24 01:03:34 +00006508 olddefine = ctxt->define;
6509 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006510 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006511 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006512 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006513 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006514
Daniel Veillard4c004142003-10-07 11:33:24 +00006515 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6516 if (schema->topgrammar == NULL) {
6517 return (schema);
6518 }
6519 /*
6520 * Link the new grammar in the tree
6521 */
6522 ret->parent = ctxt->grammar;
6523 if (ctxt->grammar != NULL) {
6524 tmp = ctxt->grammar->children;
6525 if (tmp == NULL) {
6526 ctxt->grammar->children = ret;
6527 } else {
6528 while (tmp->next != NULL)
6529 tmp = tmp->next;
6530 tmp->next = ret;
6531 }
6532 }
6533 old = ctxt->grammar;
6534 ctxt->grammar = ret;
6535 xmlRelaxNGParseStart(ctxt, node);
6536 if (old != NULL)
6537 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006538 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006539 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006540 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006541 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6542 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6543 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6544 while ((schema->topgrammar->start != NULL) &&
6545 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6546 (schema->topgrammar->start->next != NULL))
6547 schema->topgrammar->start =
6548 schema->topgrammar->start->content;
6549 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6550 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6551 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006552 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006553#ifdef DEBUG
6554 if (schema == NULL)
6555 xmlGenericError(xmlGenericErrorContext,
6556 "xmlRelaxNGParseDocument() failed\n");
6557#endif
6558
6559 return (schema);
6560}
6561
6562/************************************************************************
6563 * *
6564 * Reading RelaxNGs *
6565 * *
6566 ************************************************************************/
6567
6568/**
6569 * xmlRelaxNGNewParserCtxt:
6570 * @URL: the location of the schema
6571 *
6572 * Create an XML RelaxNGs parse context for that file/resource expected
6573 * to contain an XML RelaxNGs file.
6574 *
6575 * Returns the parser context or NULL in case of error
6576 */
6577xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006578xmlRelaxNGNewParserCtxt(const char *URL)
6579{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006580 xmlRelaxNGParserCtxtPtr ret;
6581
6582 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006583 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006584
Daniel Veillard4c004142003-10-07 11:33:24 +00006585 ret =
6586 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006587 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006588 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006589 return (NULL);
6590 }
6591 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006592 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006593 ret->error = xmlGenericError;
6594 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006595 return (ret);
6596}
6597
6598/**
6599 * xmlRelaxNGNewMemParserCtxt:
6600 * @buffer: a pointer to a char array containing the schemas
6601 * @size: the size of the array
6602 *
6603 * Create an XML RelaxNGs parse context for that memory buffer expected
6604 * to contain an XML RelaxNGs file.
6605 *
6606 * Returns the parser context or NULL in case of error
6607 */
6608xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006609xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6610{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006611 xmlRelaxNGParserCtxtPtr ret;
6612
6613 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006614 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006615
Daniel Veillard4c004142003-10-07 11:33:24 +00006616 ret =
6617 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006618 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006619 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006620 return (NULL);
6621 }
6622 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6623 ret->buffer = buffer;
6624 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006625 ret->error = xmlGenericError;
6626 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006627 return (ret);
6628}
6629
6630/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006631 * xmlRelaxNGNewDocParserCtxt:
6632 * @doc: a preparsed document tree
6633 *
6634 * Create an XML RelaxNGs parser context for that document.
6635 * Note: since the process of compiling a RelaxNG schemas modifies the
6636 * document, the @doc parameter is duplicated internally.
6637 *
6638 * Returns the parser context or NULL in case of error
6639 */
6640xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006641xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6642{
Daniel Veillard33300b42003-04-17 09:09:19 +00006643 xmlRelaxNGParserCtxtPtr ret;
6644 xmlDocPtr copy;
6645
6646 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006647 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006648 copy = xmlCopyDoc(doc, 1);
6649 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006650 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006651
Daniel Veillard4c004142003-10-07 11:33:24 +00006652 ret =
6653 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006654 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006655 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006656 return (NULL);
6657 }
6658 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6659 ret->document = copy;
6660 ret->userData = xmlGenericErrorContext;
6661 return (ret);
6662}
6663
6664/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006665 * xmlRelaxNGFreeParserCtxt:
6666 * @ctxt: the schema parser context
6667 *
6668 * Free the resources associated to the schema parser context
6669 */
6670void
Daniel Veillard4c004142003-10-07 11:33:24 +00006671xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6672{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006673 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006674 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006675 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006676 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006677 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006678 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006679 if (ctxt->interleaves != NULL)
6680 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006681 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006682 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006683 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006684 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006685 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006686 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006687 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006688 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006689 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006690 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006691
Daniel Veillard4c004142003-10-07 11:33:24 +00006692 for (i = 0; i < ctxt->defNr; i++)
6693 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6694 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006695 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006696 xmlFree(ctxt);
6697}
6698
Daniel Veillard6eadf632003-01-23 18:29:16 +00006699/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006700 * xmlRelaxNGNormExtSpace:
6701 * @value: a value
6702 *
6703 * Removes the leading and ending spaces of the value
6704 * The string is modified "in situ"
6705 */
6706static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006707xmlRelaxNGNormExtSpace(xmlChar * value)
6708{
Daniel Veillardd2298792003-02-14 16:54:11 +00006709 xmlChar *start = value;
6710 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006711
Daniel Veillard4c004142003-10-07 11:33:24 +00006712 if (value == NULL)
6713 return;
6714
William M. Brack76e95df2003-10-18 16:20:14 +00006715 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006716 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006717 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006718 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006719 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006720 cur++;
6721 if (*cur == 0)
6722 return;
6723 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006724 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006725 cur++;
6726 if (*cur == 0) {
6727 *start = 0;
6728 return;
6729 }
6730 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006731 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006732 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006733 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006734 *start++ = *cur++;
6735 if (*cur == 0) {
6736 *start = 0;
6737 return;
6738 }
6739 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006740 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006741 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006742 if (*cur == 0) {
6743 *start = 0;
6744 return;
6745 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006746 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006747 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006748 }
6749}
6750
6751/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006752 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006753 * @ctxt: a Relax-NG parser context
6754 * @node: a Relax-NG node
6755 *
6756 * Check all the attributes on the given node
6757 */
6758static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006759xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6760{
Daniel Veillardd2298792003-02-14 16:54:11 +00006761 xmlAttrPtr cur, next;
6762
6763 cur = node->properties;
6764 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006765 next = cur->next;
6766 if ((cur->ns == NULL) ||
6767 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6768 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6769 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6770 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6771 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6772 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6773 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6774 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6775 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6776 "Attribute %s is not allowed on %s\n",
6777 cur->name, node->name);
6778 }
6779 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6780 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6781 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6782 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6783 "Attribute %s is not allowed on %s\n",
6784 cur->name, node->name);
6785 }
6786 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6787 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6788 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6789 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6790 "Attribute %s is not allowed on %s\n",
6791 cur->name, node->name);
6792 }
6793 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6794 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6795 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6796 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6797 "Attribute %s is not allowed on %s\n",
6798 cur->name, node->name);
6799 }
6800 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6801 xmlChar *val;
6802 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006803
Daniel Veillard4c004142003-10-07 11:33:24 +00006804 val = xmlNodeListGetString(node->doc, cur->children, 1);
6805 if (val != NULL) {
6806 if (val[0] != 0) {
6807 uri = xmlParseURI((const char *) val);
6808 if (uri == NULL) {
6809 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6810 "Attribute %s contains invalid URI %s\n",
6811 cur->name, val);
6812 } else {
6813 if (uri->scheme == NULL) {
6814 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6815 "Attribute %s URI %s is not absolute\n",
6816 cur->name, val);
6817 }
6818 if (uri->fragment != NULL) {
6819 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6820 "Attribute %s URI %s has a fragment ID\n",
6821 cur->name, val);
6822 }
6823 xmlFreeURI(uri);
6824 }
6825 }
6826 xmlFree(val);
6827 }
6828 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6829 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6830 "Unknown attribute %s on %s\n", cur->name,
6831 node->name);
6832 }
6833 }
6834 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006835 }
6836}
6837
6838/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006839 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006840 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006841 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006842 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006843 * Cleanup the subtree from unwanted nodes for parsing, resolve
6844 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006845 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006846static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006847xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6848{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006849 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006850
Daniel Veillard6eadf632003-01-23 18:29:16 +00006851 delete = NULL;
6852 cur = root;
6853 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006854 if (delete != NULL) {
6855 xmlUnlinkNode(delete);
6856 xmlFreeNode(delete);
6857 delete = NULL;
6858 }
6859 if (cur->type == XML_ELEMENT_NODE) {
6860 /*
6861 * Simplification 4.1. Annotations
6862 */
6863 if ((cur->ns == NULL) ||
6864 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6865 if ((cur->parent != NULL) &&
6866 (cur->parent->type == XML_ELEMENT_NODE) &&
6867 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6868 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6869 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6870 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6871 "element %s doesn't allow foreign elements\n",
6872 cur->parent->name, NULL);
6873 }
6874 delete = cur;
6875 goto skip_children;
6876 } else {
6877 xmlRelaxNGCleanupAttributes(ctxt, cur);
6878 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6879 xmlChar *href, *ns, *base, *URL;
6880 xmlRelaxNGDocumentPtr docu;
6881 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006882 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006883
Daniel Veillard4c004142003-10-07 11:33:24 +00006884 ns = xmlGetProp(cur, BAD_CAST "ns");
6885 if (ns == NULL) {
6886 tmp = cur->parent;
6887 while ((tmp != NULL) &&
6888 (tmp->type == XML_ELEMENT_NODE)) {
6889 ns = xmlGetProp(tmp, BAD_CAST "ns");
6890 if (ns != NULL)
6891 break;
6892 tmp = tmp->parent;
6893 }
6894 }
6895 href = xmlGetProp(cur, BAD_CAST "href");
6896 if (href == NULL) {
6897 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6898 "xmlRelaxNGParse: externalRef has no href attribute\n",
6899 NULL, NULL);
6900 delete = cur;
6901 goto skip_children;
6902 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006903 uri = xmlParseURI((const char *) href);
6904 if (uri == NULL) {
6905 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6906 "Incorrect URI for externalRef %s\n",
6907 href, NULL);
6908 if (href != NULL)
6909 xmlFree(href);
6910 delete = cur;
6911 goto skip_children;
6912 }
6913 if (uri->fragment != NULL) {
6914 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6915 "Fragment forbidden in URI for externalRef %s\n",
6916 href, NULL);
6917 xmlFreeURI(uri);
6918 if (href != NULL)
6919 xmlFree(href);
6920 delete = cur;
6921 goto skip_children;
6922 }
6923 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006924 base = xmlNodeGetBase(cur->doc, cur);
6925 URL = xmlBuildURI(href, base);
6926 if (URL == NULL) {
6927 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6928 "Failed to compute URL for externalRef %s\n",
6929 href, NULL);
6930 if (href != NULL)
6931 xmlFree(href);
6932 if (base != NULL)
6933 xmlFree(base);
6934 delete = cur;
6935 goto skip_children;
6936 }
6937 if (href != NULL)
6938 xmlFree(href);
6939 if (base != NULL)
6940 xmlFree(base);
6941 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6942 if (docu == NULL) {
6943 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6944 "Failed to load externalRef %s\n", URL,
6945 NULL);
6946 xmlFree(URL);
6947 delete = cur;
6948 goto skip_children;
6949 }
6950 if (ns != NULL)
6951 xmlFree(ns);
6952 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006953 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006954 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6955 xmlChar *href, *ns, *base, *URL;
6956 xmlRelaxNGIncludePtr incl;
6957 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006958
Daniel Veillard4c004142003-10-07 11:33:24 +00006959 href = xmlGetProp(cur, BAD_CAST "href");
6960 if (href == NULL) {
6961 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6962 "xmlRelaxNGParse: include has no href attribute\n",
6963 NULL, NULL);
6964 delete = cur;
6965 goto skip_children;
6966 }
6967 base = xmlNodeGetBase(cur->doc, cur);
6968 URL = xmlBuildURI(href, base);
6969 if (URL == NULL) {
6970 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6971 "Failed to compute URL for include %s\n",
6972 href, NULL);
6973 if (href != NULL)
6974 xmlFree(href);
6975 if (base != NULL)
6976 xmlFree(base);
6977 delete = cur;
6978 goto skip_children;
6979 }
6980 if (href != NULL)
6981 xmlFree(href);
6982 if (base != NULL)
6983 xmlFree(base);
6984 ns = xmlGetProp(cur, BAD_CAST "ns");
6985 if (ns == NULL) {
6986 tmp = cur->parent;
6987 while ((tmp != NULL) &&
6988 (tmp->type == XML_ELEMENT_NODE)) {
6989 ns = xmlGetProp(tmp, BAD_CAST "ns");
6990 if (ns != NULL)
6991 break;
6992 tmp = tmp->parent;
6993 }
6994 }
6995 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6996 if (ns != NULL)
6997 xmlFree(ns);
6998 if (incl == NULL) {
6999 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7000 "Failed to load include %s\n", URL,
7001 NULL);
7002 xmlFree(URL);
7003 delete = cur;
7004 goto skip_children;
7005 }
7006 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007007 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007008 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7009 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7010 {
7011 xmlChar *name, *ns;
7012 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007013
Daniel Veillard4c004142003-10-07 11:33:24 +00007014 /*
7015 * Simplification 4.8. name attribute of element
7016 * and attribute elements
7017 */
7018 name = xmlGetProp(cur, BAD_CAST "name");
7019 if (name != NULL) {
7020 if (cur->children == NULL) {
7021 text =
7022 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7023 name);
7024 } else {
7025 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007026
Daniel Veillard4c004142003-10-07 11:33:24 +00007027 node = xmlNewNode(cur->ns, BAD_CAST "name");
7028 if (node != NULL) {
7029 xmlAddPrevSibling(cur->children, node);
7030 text = xmlNewText(name);
7031 xmlAddChild(node, text);
7032 text = node;
7033 }
7034 }
7035 if (text == NULL) {
7036 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7037 "Failed to create a name %s element\n",
7038 name, NULL);
7039 }
7040 xmlUnsetProp(cur, BAD_CAST "name");
7041 xmlFree(name);
7042 ns = xmlGetProp(cur, BAD_CAST "ns");
7043 if (ns != NULL) {
7044 if (text != NULL) {
7045 xmlSetProp(text, BAD_CAST "ns", ns);
7046 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7047 }
7048 xmlFree(ns);
7049 } else if (xmlStrEqual(cur->name,
7050 BAD_CAST "attribute")) {
7051 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7052 }
7053 }
7054 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7055 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7056 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7057 /*
7058 * Simplification 4.8. name attribute of element
7059 * and attribute elements
7060 */
7061 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7062 xmlNodePtr node;
7063 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007064
Daniel Veillard4c004142003-10-07 11:33:24 +00007065 node = cur->parent;
7066 while ((node != NULL) &&
7067 (node->type == XML_ELEMENT_NODE)) {
7068 ns = xmlGetProp(node, BAD_CAST "ns");
7069 if (ns != NULL) {
7070 break;
7071 }
7072 node = node->parent;
7073 }
7074 if (ns == NULL) {
7075 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7076 } else {
7077 xmlSetProp(cur, BAD_CAST "ns", ns);
7078 xmlFree(ns);
7079 }
7080 }
7081 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7082 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007083
Daniel Veillard4c004142003-10-07 11:33:24 +00007084 /*
7085 * Simplification: 4.10. QNames
7086 */
7087 name = xmlNodeGetContent(cur);
7088 if (name != NULL) {
7089 local = xmlSplitQName2(name, &prefix);
7090 if (local != NULL) {
7091 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007092
Daniel Veillard4c004142003-10-07 11:33:24 +00007093 ns = xmlSearchNs(cur->doc, cur, prefix);
7094 if (ns == NULL) {
7095 xmlRngPErr(ctxt, cur,
7096 XML_RNGP_PREFIX_UNDEFINED,
7097 "xmlRelaxNGParse: no namespace for prefix %s\n",
7098 prefix, NULL);
7099 } else {
7100 xmlSetProp(cur, BAD_CAST "ns",
7101 ns->href);
7102 xmlNodeSetContent(cur, local);
7103 }
7104 xmlFree(local);
7105 xmlFree(prefix);
7106 }
7107 xmlFree(name);
7108 }
7109 }
7110 /*
7111 * 4.16
7112 */
7113 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7114 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7115 xmlRngPErr(ctxt, cur,
7116 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7117 "Found nsName/except//nsName forbidden construct\n",
7118 NULL, NULL);
7119 }
7120 }
7121 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7122 (cur != root)) {
7123 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007124
Daniel Veillard4c004142003-10-07 11:33:24 +00007125 /*
7126 * 4.16
7127 */
7128 if ((cur->parent != NULL) &&
7129 (xmlStrEqual
7130 (cur->parent->name, BAD_CAST "anyName"))) {
7131 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7132 xmlRelaxNGCleanupTree(ctxt, cur);
7133 ctxt->flags = oldflags;
7134 goto skip_children;
7135 } else if ((cur->parent != NULL) &&
7136 (xmlStrEqual
7137 (cur->parent->name, BAD_CAST "nsName"))) {
7138 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7139 xmlRelaxNGCleanupTree(ctxt, cur);
7140 ctxt->flags = oldflags;
7141 goto skip_children;
7142 }
7143 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7144 /*
7145 * 4.16
7146 */
7147 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7148 xmlRngPErr(ctxt, cur,
7149 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7150 "Found anyName/except//anyName forbidden construct\n",
7151 NULL, NULL);
7152 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7153 xmlRngPErr(ctxt, cur,
7154 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7155 "Found nsName/except//anyName forbidden construct\n",
7156 NULL, NULL);
7157 }
7158 }
7159 /*
7160 * Thisd is not an else since "include" is transformed
7161 * into a div
7162 */
7163 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7164 xmlChar *ns;
7165 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007166
Daniel Veillard4c004142003-10-07 11:33:24 +00007167 /*
7168 * implements rule 4.11
7169 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007170
Daniel Veillard4c004142003-10-07 11:33:24 +00007171 ns = xmlGetProp(cur, BAD_CAST "ns");
7172
7173 child = cur->children;
7174 ins = cur;
7175 while (child != NULL) {
7176 if (ns != NULL) {
7177 if (!xmlHasProp(child, BAD_CAST "ns")) {
7178 xmlSetProp(child, BAD_CAST "ns", ns);
7179 }
7180 }
7181 tmp = child->next;
7182 xmlUnlinkNode(child);
7183 ins = xmlAddNextSibling(ins, child);
7184 child = tmp;
7185 }
7186 if (ns != NULL)
7187 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007188 /*
7189 * Since we are about to delete cur, if it's nsDef is non-NULL we
7190 * need to preserve it (it contains the ns definitions for the
7191 * children we just moved). We'll just stick it on to the end
7192 * of cur->parent's list, since it's never going to be re-serialized
7193 * (bug 143738).
7194 */
7195 if (cur->nsDef != NULL) {
7196 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7197 while (parDef->next != NULL)
7198 parDef = parDef->next;
7199 parDef->next = cur->nsDef;
7200 cur->nsDef = NULL;
7201 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007202 delete = cur;
7203 goto skip_children;
7204 }
7205 }
7206 }
7207 /*
7208 * Simplification 4.2 whitespaces
7209 */
7210 else if ((cur->type == XML_TEXT_NODE) ||
7211 (cur->type == XML_CDATA_SECTION_NODE)) {
7212 if (IS_BLANK_NODE(cur)) {
7213 if (cur->parent->type == XML_ELEMENT_NODE) {
7214 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7215 &&
7216 (!xmlStrEqual
7217 (cur->parent->name, BAD_CAST "param")))
7218 delete = cur;
7219 } else {
7220 delete = cur;
7221 goto skip_children;
7222 }
7223 }
7224 } else {
7225 delete = cur;
7226 goto skip_children;
7227 }
7228
7229 /*
7230 * Skip to next node
7231 */
7232 if (cur->children != NULL) {
7233 if ((cur->children->type != XML_ENTITY_DECL) &&
7234 (cur->children->type != XML_ENTITY_REF_NODE) &&
7235 (cur->children->type != XML_ENTITY_NODE)) {
7236 cur = cur->children;
7237 continue;
7238 }
7239 }
7240 skip_children:
7241 if (cur->next != NULL) {
7242 cur = cur->next;
7243 continue;
7244 }
7245
7246 do {
7247 cur = cur->parent;
7248 if (cur == NULL)
7249 break;
7250 if (cur == root) {
7251 cur = NULL;
7252 break;
7253 }
7254 if (cur->next != NULL) {
7255 cur = cur->next;
7256 break;
7257 }
7258 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007259 }
7260 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007261 xmlUnlinkNode(delete);
7262 xmlFreeNode(delete);
7263 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007264 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007265}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007266
Daniel Veillardc5312d72003-02-21 17:14:10 +00007267/**
7268 * xmlRelaxNGCleanupDoc:
7269 * @ctxt: a Relax-NG parser context
7270 * @doc: an xmldocPtr document pointer
7271 *
7272 * Cleanup the document from unwanted nodes for parsing, resolve
7273 * Include and externalRef lookups.
7274 *
7275 * Returns the cleaned up document or NULL in case of error
7276 */
7277static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007278xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7279{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007280 xmlNodePtr root;
7281
7282 /*
7283 * Extract the root
7284 */
7285 root = xmlDocGetRootElement(doc);
7286 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007287 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7288 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007289 return (NULL);
7290 }
7291 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007292 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007293}
7294
7295/**
7296 * xmlRelaxNGParse:
7297 * @ctxt: a Relax-NG parser context
7298 *
7299 * parse a schema definition resource and build an internal
7300 * XML Shema struture which can be used to validate instances.
7301 * *WARNING* this interface is highly subject to change
7302 *
7303 * Returns the internal XML RelaxNG structure built from the resource or
7304 * NULL in case of error
7305 */
7306xmlRelaxNGPtr
7307xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7308{
7309 xmlRelaxNGPtr ret = NULL;
7310 xmlDocPtr doc;
7311 xmlNodePtr root;
7312
7313 xmlRelaxNGInitTypes();
7314
7315 if (ctxt == NULL)
7316 return (NULL);
7317
7318 /*
7319 * First step is to parse the input document into an DOM/Infoset
7320 */
7321 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007322 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007323 if (doc == NULL) {
7324 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7325 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7326 NULL);
7327 return (NULL);
7328 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007329 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007330 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007331 if (doc == NULL) {
7332 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7333 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7334 NULL);
7335 return (NULL);
7336 }
7337 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7338 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007339 } else if (ctxt->document != NULL) {
7340 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007341 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007342 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7343 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7344 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007345 }
7346 ctxt->document = doc;
7347
7348 /*
7349 * Some preprocessing of the document content
7350 */
7351 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7352 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007353 xmlFreeDoc(ctxt->document);
7354 ctxt->document = NULL;
7355 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007356 }
7357
Daniel Veillard6eadf632003-01-23 18:29:16 +00007358 /*
7359 * Then do the parsing for good
7360 */
7361 root = xmlDocGetRootElement(doc);
7362 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007363 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7364 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7365 ctxt->URL, NULL);
7366 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007367 return (NULL);
7368 }
7369 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007370 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007371 xmlFreeDoc(doc);
7372 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007373 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007374
7375 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007376 * Check the ref/defines links
7377 */
7378 /*
7379 * try to preprocess interleaves
7380 */
7381 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007382 xmlHashScan(ctxt->interleaves,
7383 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007384 }
7385
7386 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007387 * if there was a parsing error return NULL
7388 */
7389 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007390 xmlRelaxNGFree(ret);
7391 ctxt->document = NULL;
7392 xmlFreeDoc(doc);
7393 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007394 }
7395
7396 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007397 * try to compile (parts of) the schemas
7398 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007399 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7400 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007401 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007402
Daniel Veillard4c004142003-10-07 11:33:24 +00007403 def = xmlRelaxNGNewDefine(ctxt, NULL);
7404 if (def != NULL) {
7405 def->type = XML_RELAXNG_START;
7406 def->content = ret->topgrammar->start;
7407 ret->topgrammar->start = def;
7408 }
7409 }
7410 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007411 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007412
7413 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007414 * Transfer the pointer for cleanup at the schema level.
7415 */
7416 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007417 ctxt->document = NULL;
7418 ret->documents = ctxt->documents;
7419 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007420
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007421 ret->includes = ctxt->includes;
7422 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007423 ret->defNr = ctxt->defNr;
7424 ret->defTab = ctxt->defTab;
7425 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007426 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007427 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007428
7429 return (ret);
7430}
Daniel Veillard4c004142003-10-07 11:33:24 +00007431
Daniel Veillard6eadf632003-01-23 18:29:16 +00007432/**
7433 * xmlRelaxNGSetParserErrors:
7434 * @ctxt: a Relax-NG validation context
7435 * @err: the error callback
7436 * @warn: the warning callback
7437 * @ctx: contextual data for the callbacks
7438 *
7439 * Set the callback functions used to handle errors for a validation context
7440 */
7441void
7442xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007443 xmlRelaxNGValidityErrorFunc err,
7444 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7445{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007446 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007447 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007448 ctxt->error = err;
7449 ctxt->warning = warn;
7450 ctxt->userData = ctx;
7451}
Daniel Veillard409a8142003-07-18 15:16:57 +00007452
7453/**
7454 * xmlRelaxNGGetParserErrors:
7455 * @ctxt: a Relax-NG validation context
7456 * @err: the error callback result
7457 * @warn: the warning callback result
7458 * @ctx: contextual data for the callbacks result
7459 *
7460 * Get the callback information used to handle errors for a validation context
7461 *
7462 * Returns -1 in case of failure, 0 otherwise.
7463 */
7464int
7465xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007466 xmlRelaxNGValidityErrorFunc * err,
7467 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7468{
Daniel Veillard409a8142003-07-18 15:16:57 +00007469 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007470 return (-1);
7471 if (err != NULL)
7472 *err = ctxt->error;
7473 if (warn != NULL)
7474 *warn = ctxt->warning;
7475 if (ctx != NULL)
7476 *ctx = ctxt->userData;
7477 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007478}
7479
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007480#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007481
Daniel Veillard6eadf632003-01-23 18:29:16 +00007482/************************************************************************
7483 * *
7484 * Dump back a compiled form *
7485 * *
7486 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007487static void xmlRelaxNGDumpDefine(FILE * output,
7488 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007489
7490/**
7491 * xmlRelaxNGDumpDefines:
7492 * @output: the file output
7493 * @defines: a list of define structures
7494 *
7495 * Dump a RelaxNG structure back
7496 */
7497static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007498xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7499{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007500 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007501 xmlRelaxNGDumpDefine(output, defines);
7502 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007503 }
7504}
7505
7506/**
7507 * xmlRelaxNGDumpDefine:
7508 * @output: the file output
7509 * @define: a define structure
7510 *
7511 * Dump a RelaxNG structure back
7512 */
7513static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007514xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7515{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007516 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007517 return;
7518 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007519 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007520 fprintf(output, "<empty/>\n");
7521 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007522 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007523 fprintf(output, "<notAllowed/>\n");
7524 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007525 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007526 fprintf(output, "<text/>\n");
7527 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007528 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007529 fprintf(output, "<element>\n");
7530 if (define->name != NULL) {
7531 fprintf(output, "<name");
7532 if (define->ns != NULL)
7533 fprintf(output, " ns=\"%s\"", define->ns);
7534 fprintf(output, ">%s</name>\n", define->name);
7535 }
7536 xmlRelaxNGDumpDefines(output, define->attrs);
7537 xmlRelaxNGDumpDefines(output, define->content);
7538 fprintf(output, "</element>\n");
7539 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007540 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007541 fprintf(output, "<list>\n");
7542 xmlRelaxNGDumpDefines(output, define->content);
7543 fprintf(output, "</list>\n");
7544 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007545 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007546 fprintf(output, "<oneOrMore>\n");
7547 xmlRelaxNGDumpDefines(output, define->content);
7548 fprintf(output, "</oneOrMore>\n");
7549 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007550 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007551 fprintf(output, "<zeroOrMore>\n");
7552 xmlRelaxNGDumpDefines(output, define->content);
7553 fprintf(output, "</zeroOrMore>\n");
7554 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007555 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007556 fprintf(output, "<choice>\n");
7557 xmlRelaxNGDumpDefines(output, define->content);
7558 fprintf(output, "</choice>\n");
7559 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007560 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007561 fprintf(output, "<group>\n");
7562 xmlRelaxNGDumpDefines(output, define->content);
7563 fprintf(output, "</group>\n");
7564 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007565 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007566 fprintf(output, "<interleave>\n");
7567 xmlRelaxNGDumpDefines(output, define->content);
7568 fprintf(output, "</interleave>\n");
7569 break;
7570 case XML_RELAXNG_OPTIONAL:
7571 fprintf(output, "<optional>\n");
7572 xmlRelaxNGDumpDefines(output, define->content);
7573 fprintf(output, "</optional>\n");
7574 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007575 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007576 fprintf(output, "<attribute>\n");
7577 xmlRelaxNGDumpDefines(output, define->content);
7578 fprintf(output, "</attribute>\n");
7579 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007580 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007581 fprintf(output, "<define");
7582 if (define->name != NULL)
7583 fprintf(output, " name=\"%s\"", define->name);
7584 fprintf(output, ">\n");
7585 xmlRelaxNGDumpDefines(output, define->content);
7586 fprintf(output, "</define>\n");
7587 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007588 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007589 fprintf(output, "<ref");
7590 if (define->name != NULL)
7591 fprintf(output, " name=\"%s\"", define->name);
7592 fprintf(output, ">\n");
7593 xmlRelaxNGDumpDefines(output, define->content);
7594 fprintf(output, "</ref>\n");
7595 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007596 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007597 fprintf(output, "<parentRef");
7598 if (define->name != NULL)
7599 fprintf(output, " name=\"%s\"", define->name);
7600 fprintf(output, ">\n");
7601 xmlRelaxNGDumpDefines(output, define->content);
7602 fprintf(output, "</parentRef>\n");
7603 break;
7604 case XML_RELAXNG_EXTERNALREF:
7605 fprintf(output, "<externalRef>");
7606 xmlRelaxNGDumpDefines(output, define->content);
7607 fprintf(output, "</externalRef>\n");
7608 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007609 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007610 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007611 TODO break;
7612 case XML_RELAXNG_START:
7613 case XML_RELAXNG_EXCEPT:
7614 case XML_RELAXNG_PARAM:
7615 TODO break;
7616 case XML_RELAXNG_NOOP:
7617 xmlRelaxNGDumpDefines(output, define->content);
7618 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007619 }
7620}
Daniel Veillard4c004142003-10-07 11:33:24 +00007621
Daniel Veillard6eadf632003-01-23 18:29:16 +00007622/**
7623 * xmlRelaxNGDumpGrammar:
7624 * @output: the file output
7625 * @grammar: a grammar structure
7626 * @top: is this a top grammar
7627 *
7628 * Dump a RelaxNG structure back
7629 */
7630static void
7631xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7632{
7633 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007634 return;
7635
Daniel Veillard6eadf632003-01-23 18:29:16 +00007636 fprintf(output, "<grammar");
7637 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007638 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7639 switch (grammar->combine) {
7640 case XML_RELAXNG_COMBINE_UNDEFINED:
7641 break;
7642 case XML_RELAXNG_COMBINE_CHOICE:
7643 fprintf(output, " combine=\"choice\"");
7644 break;
7645 case XML_RELAXNG_COMBINE_INTERLEAVE:
7646 fprintf(output, " combine=\"interleave\"");
7647 break;
7648 default:
7649 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007650 }
7651 fprintf(output, ">\n");
7652 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007653 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007654 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007655 fprintf(output, "<start>\n");
7656 xmlRelaxNGDumpDefine(output, grammar->start);
7657 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007658 }
7659 /* TODO ? Dump the defines ? */
7660 fprintf(output, "</grammar>\n");
7661}
7662
7663/**
7664 * xmlRelaxNGDump:
7665 * @output: the file output
7666 * @schema: a schema structure
7667 *
7668 * Dump a RelaxNG structure back
7669 */
7670void
7671xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7672{
7673 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007674 fprintf(output, "RelaxNG empty or failed to compile\n");
7675 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007676 }
7677 fprintf(output, "RelaxNG: ");
7678 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007679 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007680 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007681 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007682 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007683 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007684 }
7685 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007686 fprintf(output, "RelaxNG has no top grammar\n");
7687 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007688 }
7689 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7690}
7691
Daniel Veillardfebcca42003-02-16 15:44:18 +00007692/**
7693 * xmlRelaxNGDumpTree:
7694 * @output: the file output
7695 * @schema: a schema structure
7696 *
7697 * Dump the transformed RelaxNG tree.
7698 */
7699void
7700xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7701{
7702 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007703 fprintf(output, "RelaxNG empty or failed to compile\n");
7704 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007705 }
7706 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007707 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007708 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007709 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007710 }
7711}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007712#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007713
Daniel Veillard6eadf632003-01-23 18:29:16 +00007714/************************************************************************
7715 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007716 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007717 * *
7718 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007719static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7720 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007721
7722/**
7723 * xmlRelaxNGValidateCompiledCallback:
7724 * @exec: the regular expression instance
7725 * @token: the token which matched
7726 * @transdata: callback data, the define for the subelement if available
7727 @ @inputdata: callback data, the Relax NG validation context
7728 *
7729 * Handle the callback and if needed validate the element children.
7730 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007731static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007732xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007733 const xmlChar * token,
7734 void *transdata, void *inputdata)
7735{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007736 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7737 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7738 int ret;
7739
7740#ifdef DEBUG_COMPILE
7741 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007742 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007743#endif
7744 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007745 fprintf(stderr, "callback on %s missing context\n", token);
7746 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7747 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7748 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007749 }
7750 if (define == NULL) {
7751 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007752 return;
7753 fprintf(stderr, "callback on %s missing define\n", token);
7754 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7755 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7756 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007757 }
7758 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007759 fprintf(stderr, "callback on %s missing info\n", token);
7760 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7761 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7762 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007763 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007764 fprintf(stderr, "callback on %s define is not element\n", token);
7765 if (ctxt->errNo == XML_RELAXNG_OK)
7766 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7767 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007768 }
7769 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007770 if (ret != 0)
7771 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007772}
7773
7774/**
7775 * xmlRelaxNGValidateCompiledContent:
7776 * @ctxt: the RelaxNG validation context
7777 * @regexp: the regular expression as compiled
7778 * @content: list of children to test against the regexp
7779 *
7780 * Validate the content model of an element or start using the regexp
7781 *
7782 * Returns 0 in case of success, -1 in case of error.
7783 */
7784static int
7785xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007786 xmlRegexpPtr regexp, xmlNodePtr content)
7787{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007788 xmlRegExecCtxtPtr exec;
7789 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007790 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007791 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007792
7793 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007794 return (-1);
7795 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007796 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007797 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007798 cur = content;
7799 while (cur != NULL) {
7800 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007801 switch (cur->type) {
7802 case XML_TEXT_NODE:
7803 case XML_CDATA_SECTION_NODE:
7804 if (xmlIsBlankNode(cur))
7805 break;
7806 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7807 if (ret < 0) {
7808 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7809 cur->parent->name);
7810 }
7811 break;
7812 case XML_ELEMENT_NODE:
7813 if (cur->ns != NULL) {
7814 ret = xmlRegExecPushString2(exec, cur->name,
7815 cur->ns->href, ctxt);
7816 } else {
7817 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7818 }
7819 if (ret < 0) {
7820 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7821 }
7822 break;
7823 default:
7824 break;
7825 }
7826 if (ret < 0)
7827 break;
7828 /*
7829 * Switch to next element
7830 */
7831 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007832 }
7833 ret = xmlRegExecPushString(exec, NULL, NULL);
7834 if (ret == 1) {
7835 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007836 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007837 } else if (ret == 0) {
7838 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007839 * TODO: get some of the names needed to exit the current state of exec
7840 */
7841 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7842 ret = -1;
7843 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7844 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007845 } else {
7846 ret = -1;
7847 }
7848 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007849 /*
7850 * There might be content model errors outside of the pure
7851 * regexp validation, e.g. for attribute values.
7852 */
7853 if ((ret == 0) && (ctxt->perr != 0)) {
7854 ret = ctxt->perr;
7855 }
7856 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007857 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007858}
7859
7860/************************************************************************
7861 * *
7862 * Progressive validation of when possible *
7863 * *
7864 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007865static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7866 xmlRelaxNGDefinePtr defines);
7867static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007868 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007869static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007870
7871/**
7872 * xmlRelaxNGElemPush:
7873 * @ctxt: the validation context
7874 * @exec: the regexp runtime for the new content model
7875 *
7876 * Push a new regexp for the current node content model on the stack
7877 *
7878 * Returns 0 in case of success and -1 in case of error.
7879 */
7880static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007881xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7882{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007883 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007884 ctxt->elemMax = 10;
7885 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7886 sizeof
7887 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007888 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007889 xmlRngVErrMemory(ctxt, "validating\n");
7890 return (-1);
7891 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007892 }
7893 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007894 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007895 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007896 ctxt->elemMax *
7897 sizeof
7898 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007899 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007900 xmlRngVErrMemory(ctxt, "validating\n");
7901 return (-1);
7902 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007903 }
7904 ctxt->elemTab[ctxt->elemNr++] = exec;
7905 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007906 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007907}
7908
7909/**
7910 * xmlRelaxNGElemPop:
7911 * @ctxt: the validation context
7912 *
7913 * Pop the regexp of the current node content model from the stack
7914 *
7915 * Returns the exec or NULL if empty
7916 */
7917static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007918xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7919{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007920 xmlRegExecCtxtPtr ret;
7921
Daniel Veillard4c004142003-10-07 11:33:24 +00007922 if (ctxt->elemNr <= 0)
7923 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007924 ctxt->elemNr--;
7925 ret = ctxt->elemTab[ctxt->elemNr];
7926 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007927 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007928 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7929 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007930 ctxt->elem = NULL;
7931 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007932}
7933
7934/**
7935 * xmlRelaxNGValidateProgressiveCallback:
7936 * @exec: the regular expression instance
7937 * @token: the token which matched
7938 * @transdata: callback data, the define for the subelement if available
7939 @ @inputdata: callback data, the Relax NG validation context
7940 *
7941 * Handle the callback and if needed validate the element children.
7942 * some of the in/out informations are passed via the context in @inputdata.
7943 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007944static void
7945xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7946 ATTRIBUTE_UNUSED,
7947 const xmlChar * token,
7948 void *transdata, void *inputdata)
7949{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007950 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7951 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007952 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007953 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007954 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007955
7956#ifdef DEBUG_PROGRESSIVE
7957 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007958 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007959#endif
7960 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007961 fprintf(stderr, "callback on %s missing context\n", token);
7962 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007963 }
7964 ctxt->pstate = 1;
7965 if (define == NULL) {
7966 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007967 return;
7968 fprintf(stderr, "callback on %s missing define\n", token);
7969 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7970 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7971 ctxt->pstate = -1;
7972 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007973 }
7974 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007975 fprintf(stderr, "callback on %s missing info\n", token);
7976 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7977 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7978 ctxt->pstate = -1;
7979 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007980 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007981 fprintf(stderr, "callback on %s define is not element\n", token);
7982 if (ctxt->errNo == XML_RELAXNG_OK)
7983 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7984 ctxt->pstate = -1;
7985 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007986 }
7987 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007988 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7989 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7990 xmlRelaxNGDumpValidError(ctxt);
7991 ctxt->pstate = -1;
7992 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007993 }
7994 if (define->contModel == NULL) {
7995 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007996 * this node cannot be validated in a streamable fashion
7997 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00007998#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00007999 xmlGenericError(xmlGenericErrorContext,
8000 "Element '%s' validation is not streamable\n",
8001 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008002#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008003 ctxt->pstate = 0;
8004 ctxt->pdef = define;
8005 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008006 }
8007 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008008 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008009 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008010 ctxt->pstate = -1;
8011 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008012 }
8013 xmlRelaxNGElemPush(ctxt, exec);
8014
8015 /*
8016 * Validate the attributes part of the content.
8017 */
8018 state = xmlRelaxNGNewValidState(ctxt, node);
8019 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008020 ctxt->pstate = -1;
8021 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008022 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008023 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008024 ctxt->state = state;
8025 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008026 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8027 if (ret != 0) {
8028 ctxt->pstate = -1;
8029 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8030 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008031 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008032 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008033 ctxt->state->seq = NULL;
8034 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8035 if (ret != 0) {
8036 ctxt->pstate = -1;
8037 }
8038 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008039 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008040 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008041
8042 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008043
Daniel Veillard4c004142003-10-07 11:33:24 +00008044 for (i = 0; i < ctxt->states->nbState; i++) {
8045 state = ctxt->states->tabState[i];
8046 ctxt->state = state;
8047 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008048
Daniel Veillard4c004142003-10-07 11:33:24 +00008049 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8050 tmp = 0;
8051 break;
8052 }
8053 }
8054 if (tmp != 0) {
8055 /*
8056 * validation error, log the message for the "best" one
8057 */
8058 ctxt->flags |= FLAGS_IGNORABLE;
8059 xmlRelaxNGLogBestError(ctxt);
8060 }
8061 for (i = 0; i < ctxt->states->nbState; i++) {
8062 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8063 }
8064 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8065 ctxt->states = NULL;
8066 if ((ret == 0) && (tmp == -1))
8067 ctxt->pstate = -1;
8068 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008069 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008070 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008071 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8072 xmlRelaxNGDumpValidError(ctxt);
8073 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008074 }
8075 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008076}
8077
8078/**
8079 * xmlRelaxNGValidatePushElement:
8080 * @ctxt: the validation context
8081 * @doc: a document instance
8082 * @elem: an element instance
8083 *
8084 * Push a new element start on the RelaxNG validation stack.
8085 *
8086 * returns 1 if no validation problem was found or 0 if validating the
8087 * element requires a full node, and -1 in case of error.
8088 */
8089int
Daniel Veillard33300b42003-04-17 09:09:19 +00008090xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8091 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008092 xmlNodePtr elem)
8093{
8094 int ret = 1;
8095
8096 if ((ctxt == NULL) || (elem == NULL))
8097 return (-1);
8098
8099#ifdef DEBUG_PROGRESSIVE
8100 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8101#endif
8102 if (ctxt->elem == 0) {
8103 xmlRelaxNGPtr schema;
8104 xmlRelaxNGGrammarPtr grammar;
8105 xmlRegExecCtxtPtr exec;
8106 xmlRelaxNGDefinePtr define;
8107
8108 schema = ctxt->schema;
8109 if (schema == NULL) {
8110 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8111 return (-1);
8112 }
8113 grammar = schema->topgrammar;
8114 if ((grammar == NULL) || (grammar->start == NULL)) {
8115 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8116 return (-1);
8117 }
8118 define = grammar->start;
8119 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008120 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008121 return (0);
8122 }
8123 exec = xmlRegNewExecCtxt(define->contModel,
8124 xmlRelaxNGValidateProgressiveCallback,
8125 ctxt);
8126 if (exec == NULL) {
8127 return (-1);
8128 }
8129 xmlRelaxNGElemPush(ctxt, exec);
8130 }
8131 ctxt->pnode = elem;
8132 ctxt->pstate = 0;
8133 if (elem->ns != NULL) {
8134 ret =
8135 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8136 ctxt);
8137 } else {
8138 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8139 }
8140 if (ret < 0) {
8141 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8142 } else {
8143 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008144 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008145 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008146 ret = -1;
8147 else
8148 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008149 }
8150#ifdef DEBUG_PROGRESSIVE
8151 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008152 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8153 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008154#endif
8155 return (ret);
8156}
8157
8158/**
8159 * xmlRelaxNGValidatePushCData:
8160 * @ctxt: the RelaxNG validation context
8161 * @data: some character data read
8162 * @len: the lenght of the data
8163 *
8164 * check the CData parsed for validation in the current stack
8165 *
8166 * returns 1 if no validation problem was found or -1 otherwise
8167 */
8168int
8169xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008170 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008171{
8172 int ret = 1;
8173
8174 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8175 return (-1);
8176
8177#ifdef DEBUG_PROGRESSIVE
8178 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8179#endif
8180
8181 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008182 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008183 break;
8184 data++;
8185 }
8186 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008187 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008188
8189 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8190 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008191 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008192#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008193 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008194#endif
8195
Daniel Veillard4c004142003-10-07 11:33:24 +00008196 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008197 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008198 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008199}
8200
8201/**
8202 * xmlRelaxNGValidatePopElement:
8203 * @ctxt: the RelaxNG validation context
8204 * @doc: a document instance
8205 * @elem: an element instance
8206 *
8207 * Pop the element end from the RelaxNG validation stack.
8208 *
8209 * returns 1 if no validation problem was found or 0 otherwise
8210 */
8211int
8212xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8213 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008214 xmlNodePtr elem)
8215{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008216 int ret;
8217 xmlRegExecCtxtPtr exec;
8218
Daniel Veillard4c004142003-10-07 11:33:24 +00008219 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8220 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008221#ifdef DEBUG_PROGRESSIVE
8222 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8223#endif
8224 /*
8225 * verify that we reached a terminal state of the content model.
8226 */
8227 exec = xmlRelaxNGElemPop(ctxt);
8228 ret = xmlRegExecPushString(exec, NULL, NULL);
8229 if (ret == 0) {
8230 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008231 * TODO: get some of the names needed to exit the current state of exec
8232 */
8233 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8234 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008235 } else if (ret < 0) {
8236 ret = -1;
8237 } else {
8238 ret = 1;
8239 }
8240 xmlRegFreeExecCtxt(exec);
8241#ifdef DEBUG_PROGRESSIVE
8242 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008243 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8244 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008245#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008246 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008247}
8248
8249/**
8250 * xmlRelaxNGValidateFullElement:
8251 * @ctxt: the validation context
8252 * @doc: a document instance
8253 * @elem: an element instance
8254 *
8255 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8256 * 0 and the content of the node has been expanded.
8257 *
8258 * returns 1 if no validation problem was found or -1 in case of error.
8259 */
8260int
Daniel Veillard33300b42003-04-17 09:09:19 +00008261xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8262 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008263 xmlNodePtr elem)
8264{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008265 int ret;
8266 xmlRelaxNGValidStatePtr state;
8267
Daniel Veillard4c004142003-10-07 11:33:24 +00008268 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8269 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008270#ifdef DEBUG_PROGRESSIVE
8271 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8272#endif
8273 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8274 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008275 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008276 }
8277 state->seq = elem;
8278 ctxt->state = state;
8279 ctxt->errNo = XML_RELAXNG_OK;
8280 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008281 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8282 ret = -1;
8283 else
8284 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008285 xmlRelaxNGFreeValidState(ctxt, state);
8286 ctxt->state = NULL;
8287#ifdef DEBUG_PROGRESSIVE
8288 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008289 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8290 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008291#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008292 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008293}
8294
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008295/************************************************************************
8296 * *
8297 * Generic interpreted validation implementation *
8298 * *
8299 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008300static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8301 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008302
8303/**
8304 * xmlRelaxNGSkipIgnored:
8305 * @ctxt: a schema validation context
8306 * @node: the top node.
8307 *
8308 * Skip ignorable nodes in that context
8309 *
8310 * Returns the new sibling or NULL in case of error.
8311 */
8312static xmlNodePtr
8313xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008314 xmlNodePtr node)
8315{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008316 /*
8317 * TODO complete and handle entities
8318 */
8319 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008320 ((node->type == XML_COMMENT_NODE) ||
8321 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008322 (node->type == XML_XINCLUDE_START) ||
8323 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008324 (((node->type == XML_TEXT_NODE) ||
8325 (node->type == XML_CDATA_SECTION_NODE)) &&
8326 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8327 (IS_BLANK_NODE(node)))))) {
8328 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008329 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008330 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008331}
8332
8333/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008334 * xmlRelaxNGNormalize:
8335 * @ctxt: a schema validation context
8336 * @str: the string to normalize
8337 *
8338 * Implements the normalizeWhiteSpace( s ) function from
8339 * section 6.2.9 of the spec
8340 *
8341 * Returns the new string or NULL in case of error.
8342 */
8343static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008344xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8345{
Daniel Veillardedc91922003-01-26 00:52:04 +00008346 xmlChar *ret, *p;
8347 const xmlChar *tmp;
8348 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008349
Daniel Veillardedc91922003-01-26 00:52:04 +00008350 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008351 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008352 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008353 while (*tmp != 0)
8354 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008355 len = tmp - str;
8356
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008357 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008358 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008359 xmlRngVErrMemory(ctxt, "validating\n");
8360 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008361 }
8362 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008363 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008364 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008365 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008366 if (IS_BLANK_CH(*str)) {
8367 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008368 str++;
8369 if (*str == 0)
8370 break;
8371 *p++ = ' ';
8372 } else
8373 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008374 }
8375 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008376 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008377}
8378
8379/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008380 * xmlRelaxNGValidateDatatype:
8381 * @ctxt: a Relax-NG validation context
8382 * @value: the string value
8383 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008384 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008385 *
8386 * Validate the given value against the dataype
8387 *
8388 * Returns 0 if the validation succeeded or an error code.
8389 */
8390static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008391xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8392 const xmlChar * value,
8393 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8394{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008395 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008396 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008397 void *result = NULL;
8398 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008399
8400 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008401 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008402 }
8403 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008404 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008405 if ((define->attrs != NULL) &&
8406 (define->attrs->type == XML_RELAXNG_PARAM)) {
8407 ret =
8408 lib->check(lib->data, define->name, value, &result, node);
8409 } else {
8410 ret = lib->check(lib->data, define->name, value, NULL, node);
8411 }
8412 } else
8413 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008414 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008415 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8416 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8417 lib->freef(lib->data, result);
8418 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008419 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008420 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008421 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008422 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008423 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008424 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8425 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008426 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008427 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008428 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008429 if (lib->facet != NULL) {
8430 tmp = lib->facet(lib->data, define->name, cur->name,
8431 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008432 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008433 ret = -1;
8434 }
8435 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008436 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008437 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008438 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008439
Daniel Veillard4c004142003-10-07 11:33:24 +00008440 oldvalue = ctxt->state->value;
8441 oldendvalue = ctxt->state->endvalue;
8442 ctxt->state->value = (xmlChar *) value;
8443 ctxt->state->endvalue = NULL;
8444 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8445 ctxt->state->value = (xmlChar *) oldvalue;
8446 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008447 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008448 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008449 lib->freef(lib->data, result);
8450 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008451}
8452
8453/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008454 * xmlRelaxNGNextValue:
8455 * @ctxt: a Relax-NG validation context
8456 *
8457 * Skip to the next value when validating within a list
8458 *
8459 * Returns 0 if the operation succeeded or an error code.
8460 */
8461static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008462xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8463{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008464 xmlChar *cur;
8465
8466 cur = ctxt->state->value;
8467 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008468 ctxt->state->value = NULL;
8469 ctxt->state->endvalue = NULL;
8470 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008471 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008472 while (*cur != 0)
8473 cur++;
8474 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8475 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008476 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008477 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008478 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008479 ctxt->state->value = cur;
8480 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008481}
8482
8483/**
8484 * xmlRelaxNGValidateValueList:
8485 * @ctxt: a Relax-NG validation context
8486 * @defines: the list of definitions to verify
8487 *
8488 * Validate the given set of definitions for the current value
8489 *
8490 * Returns 0 if the validation succeeded or an error code.
8491 */
8492static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008493xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8494 xmlRelaxNGDefinePtr defines)
8495{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008496 int ret = 0;
8497
8498 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008499 ret = xmlRelaxNGValidateValue(ctxt, defines);
8500 if (ret != 0)
8501 break;
8502 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008503 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008504 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008505}
8506
8507/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008508 * xmlRelaxNGValidateValue:
8509 * @ctxt: a Relax-NG validation context
8510 * @define: the definition to verify
8511 *
8512 * Validate the given definition for the current value
8513 *
8514 * Returns 0 if the validation succeeded or an error code.
8515 */
8516static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008517xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8518 xmlRelaxNGDefinePtr define)
8519{
Daniel Veillardedc91922003-01-26 00:52:04 +00008520 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008521 xmlChar *value;
8522
8523 value = ctxt->state->value;
8524 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008525 case XML_RELAXNG_EMPTY:{
8526 if ((value != NULL) && (value[0] != 0)) {
8527 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008528
William M. Brack76e95df2003-10-18 16:20:14 +00008529 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008530 idx++;
8531 if (value[idx] != 0)
8532 ret = -1;
8533 }
8534 break;
8535 }
8536 case XML_RELAXNG_TEXT:
8537 break;
8538 case XML_RELAXNG_VALUE:{
8539 if (!xmlStrEqual(value, define->value)) {
8540 if (define->name != NULL) {
8541 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008542
Daniel Veillard4c004142003-10-07 11:33:24 +00008543 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8544 if ((lib != NULL) && (lib->comp != NULL)) {
8545 ret = lib->comp(lib->data, define->name,
8546 define->value, define->node,
8547 (void *) define->attrs,
8548 value, ctxt->state->node);
8549 } else
8550 ret = -1;
8551 if (ret < 0) {
8552 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8553 define->name);
8554 return (-1);
8555 } else if (ret == 1) {
8556 ret = 0;
8557 } else {
8558 ret = -1;
8559 }
8560 } else {
8561 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008562
Daniel Veillard4c004142003-10-07 11:33:24 +00008563 /*
8564 * TODO: trivial optimizations are possible by
8565 * computing at compile-time
8566 */
8567 nval = xmlRelaxNGNormalize(ctxt, define->value);
8568 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008569
Daniel Veillard4c004142003-10-07 11:33:24 +00008570 if ((nval == NULL) || (nvalue == NULL) ||
8571 (!xmlStrEqual(nval, nvalue)))
8572 ret = -1;
8573 if (nval != NULL)
8574 xmlFree(nval);
8575 if (nvalue != NULL)
8576 xmlFree(nvalue);
8577 }
8578 }
8579 if (ret == 0)
8580 xmlRelaxNGNextValue(ctxt);
8581 break;
8582 }
8583 case XML_RELAXNG_DATATYPE:{
8584 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8585 ctxt->state->seq);
8586 if (ret == 0)
8587 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008588
Daniel Veillard4c004142003-10-07 11:33:24 +00008589 break;
8590 }
8591 case XML_RELAXNG_CHOICE:{
8592 xmlRelaxNGDefinePtr list = define->content;
8593 xmlChar *oldvalue;
8594
8595 oldflags = ctxt->flags;
8596 ctxt->flags |= FLAGS_IGNORABLE;
8597
8598 oldvalue = ctxt->state->value;
8599 while (list != NULL) {
8600 ret = xmlRelaxNGValidateValue(ctxt, list);
8601 if (ret == 0) {
8602 break;
8603 }
8604 ctxt->state->value = oldvalue;
8605 list = list->next;
8606 }
8607 ctxt->flags = oldflags;
8608 if (ret != 0) {
8609 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8610 xmlRelaxNGDumpValidError(ctxt);
8611 } else {
8612 if (ctxt->errNr > 0)
8613 xmlRelaxNGPopErrors(ctxt, 0);
8614 }
8615 if (ret == 0)
8616 xmlRelaxNGNextValue(ctxt);
8617 break;
8618 }
8619 case XML_RELAXNG_LIST:{
8620 xmlRelaxNGDefinePtr list = define->content;
8621 xmlChar *oldvalue, *oldend, *val, *cur;
8622
Daniel Veillard416589a2003-02-17 17:25:42 +00008623#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008624 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008625#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008626
Daniel Veillard4c004142003-10-07 11:33:24 +00008627 oldvalue = ctxt->state->value;
8628 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008629
Daniel Veillard4c004142003-10-07 11:33:24 +00008630 val = xmlStrdup(oldvalue);
8631 if (val == NULL) {
8632 val = xmlStrdup(BAD_CAST "");
8633 }
8634 if (val == NULL) {
8635 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8636 return (-1);
8637 }
8638 cur = val;
8639 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008640 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008641 *cur = 0;
8642 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008643#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008644 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008645#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008646 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008647 *cur++ = 0;
8648 } else
8649 cur++;
8650 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008651#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008652 xmlGenericError(xmlGenericErrorContext,
8653 "list value: '%s' found %d items\n",
8654 oldvalue, nb_values);
8655 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008656#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008657 ctxt->state->endvalue = cur;
8658 cur = val;
8659 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8660 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008661
Daniel Veillard4c004142003-10-07 11:33:24 +00008662 ctxt->state->value = cur;
8663
8664 while (list != NULL) {
8665 if (ctxt->state->value == ctxt->state->endvalue)
8666 ctxt->state->value = NULL;
8667 ret = xmlRelaxNGValidateValue(ctxt, list);
8668 if (ret != 0) {
8669#ifdef DEBUG_LIST
8670 xmlGenericError(xmlGenericErrorContext,
8671 "Failed to validate value: '%s' with %d rule\n",
8672 ctxt->state->value, nb_values);
8673#endif
8674 break;
8675 }
8676#ifdef DEBUG_LIST
8677 nb_values++;
8678#endif
8679 list = list->next;
8680 }
8681
8682 if ((ret == 0) && (ctxt->state->value != NULL) &&
8683 (ctxt->state->value != ctxt->state->endvalue)) {
8684 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8685 ctxt->state->value);
8686 ret = -1;
8687 }
8688 xmlFree(val);
8689 ctxt->state->value = oldvalue;
8690 ctxt->state->endvalue = oldend;
8691 break;
8692 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008693 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008694 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8695 if (ret != 0) {
8696 break;
8697 }
8698 /* no break on purpose */
8699 case XML_RELAXNG_ZEROORMORE:{
8700 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008701
Daniel Veillard4c004142003-10-07 11:33:24 +00008702 oldflags = ctxt->flags;
8703 ctxt->flags |= FLAGS_IGNORABLE;
8704 cur = ctxt->state->value;
8705 temp = NULL;
8706 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8707 (temp != cur)) {
8708 temp = cur;
8709 ret =
8710 xmlRelaxNGValidateValueList(ctxt, define->content);
8711 if (ret != 0) {
8712 ctxt->state->value = temp;
8713 ret = 0;
8714 break;
8715 }
8716 cur = ctxt->state->value;
8717 }
8718 ctxt->flags = oldflags;
8719 if (ret != 0) {
8720 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8721 xmlRelaxNGDumpValidError(ctxt);
8722 } else {
8723 if (ctxt->errNr > 0)
8724 xmlRelaxNGPopErrors(ctxt, 0);
8725 }
8726 break;
8727 }
8728 case XML_RELAXNG_EXCEPT:{
8729 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008730
Daniel Veillard4c004142003-10-07 11:33:24 +00008731 list = define->content;
8732 while (list != NULL) {
8733 ret = xmlRelaxNGValidateValue(ctxt, list);
8734 if (ret == 0) {
8735 ret = -1;
8736 break;
8737 } else
8738 ret = 0;
8739 list = list->next;
8740 }
8741 break;
8742 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008743 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008744 case XML_RELAXNG_GROUP:{
8745 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008746
Daniel Veillard4c004142003-10-07 11:33:24 +00008747 list = define->content;
8748 while (list != NULL) {
8749 ret = xmlRelaxNGValidateValue(ctxt, list);
8750 if (ret != 0) {
8751 ret = -1;
8752 break;
8753 } else
8754 ret = 0;
8755 list = list->next;
8756 }
8757 break;
8758 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008759 case XML_RELAXNG_REF:
8760 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008761 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8762 break;
8763 default:
8764 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008765 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008766 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008767}
8768
8769/**
8770 * xmlRelaxNGValidateValueContent:
8771 * @ctxt: a Relax-NG validation context
8772 * @defines: the list of definitions to verify
8773 *
8774 * Validate the given definitions for the current value
8775 *
8776 * Returns 0 if the validation succeeded or an error code.
8777 */
8778static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008779xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8780 xmlRelaxNGDefinePtr defines)
8781{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008782 int ret = 0;
8783
8784 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008785 ret = xmlRelaxNGValidateValue(ctxt, defines);
8786 if (ret != 0)
8787 break;
8788 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008789 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008790 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008791}
8792
8793/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008794 * xmlRelaxNGAttributeMatch:
8795 * @ctxt: a Relax-NG validation context
8796 * @define: the definition to check
8797 * @prop: the attribute
8798 *
8799 * Check if the attribute matches the definition nameClass
8800 *
8801 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8802 */
8803static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008804xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8805 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8806{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008807 int ret;
8808
8809 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008810 if (!xmlStrEqual(define->name, prop->name))
8811 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008812 }
8813 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008814 if (define->ns[0] == 0) {
8815 if (prop->ns != NULL)
8816 return (0);
8817 } else {
8818 if ((prop->ns == NULL) ||
8819 (!xmlStrEqual(define->ns, prop->ns->href)))
8820 return (0);
8821 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008822 }
8823 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008824 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008825 define = define->nameClass;
8826 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008827 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008828
Daniel Veillard4c004142003-10-07 11:33:24 +00008829 list = define->content;
8830 while (list != NULL) {
8831 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8832 if (ret == 1)
8833 return (0);
8834 if (ret < 0)
8835 return (ret);
8836 list = list->next;
8837 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008838 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008839 TODO}
8840 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008841}
8842
8843/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008844 * xmlRelaxNGValidateAttribute:
8845 * @ctxt: a Relax-NG validation context
8846 * @define: the definition to verify
8847 *
8848 * Validate the given attribute definition for that node
8849 *
8850 * Returns 0 if the validation succeeded or an error code.
8851 */
8852static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008853xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8854 xmlRelaxNGDefinePtr define)
8855{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008856 int ret = 0, i;
8857 xmlChar *value, *oldvalue;
8858 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008859 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008860
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008861 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008862 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008863 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008864 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8865 tmp = ctxt->state->attrs[i];
8866 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8867 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8868 (tmp->ns == NULL)) ||
8869 ((tmp->ns != NULL) &&
8870 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8871 prop = tmp;
8872 break;
8873 }
8874 }
8875 }
8876 if (prop != NULL) {
8877 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8878 oldvalue = ctxt->state->value;
8879 oldseq = ctxt->state->seq;
8880 ctxt->state->seq = (xmlNodePtr) prop;
8881 ctxt->state->value = value;
8882 ctxt->state->endvalue = NULL;
8883 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8884 if (ctxt->state->value != NULL)
8885 value = ctxt->state->value;
8886 if (value != NULL)
8887 xmlFree(value);
8888 ctxt->state->value = oldvalue;
8889 ctxt->state->seq = oldseq;
8890 if (ret == 0) {
8891 /*
8892 * flag the attribute as processed
8893 */
8894 ctxt->state->attrs[i] = NULL;
8895 ctxt->state->nbAttrLeft--;
8896 }
8897 } else {
8898 ret = -1;
8899 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008900#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008901 xmlGenericError(xmlGenericErrorContext,
8902 "xmlRelaxNGValidateAttribute(%s): %d\n",
8903 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008904#endif
8905 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008906 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8907 tmp = ctxt->state->attrs[i];
8908 if ((tmp != NULL) &&
8909 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8910 prop = tmp;
8911 break;
8912 }
8913 }
8914 if (prop != NULL) {
8915 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8916 oldvalue = ctxt->state->value;
8917 oldseq = ctxt->state->seq;
8918 ctxt->state->seq = (xmlNodePtr) prop;
8919 ctxt->state->value = value;
8920 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8921 if (ctxt->state->value != NULL)
8922 value = ctxt->state->value;
8923 if (value != NULL)
8924 xmlFree(value);
8925 ctxt->state->value = oldvalue;
8926 ctxt->state->seq = oldseq;
8927 if (ret == 0) {
8928 /*
8929 * flag the attribute as processed
8930 */
8931 ctxt->state->attrs[i] = NULL;
8932 ctxt->state->nbAttrLeft--;
8933 }
8934 } else {
8935 ret = -1;
8936 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008937#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008938 if (define->ns != NULL) {
8939 xmlGenericError(xmlGenericErrorContext,
8940 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8941 define->ns, ret);
8942 } else {
8943 xmlGenericError(xmlGenericErrorContext,
8944 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8945 ret);
8946 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008947#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008948 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008949
8950 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008951}
8952
8953/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008954 * xmlRelaxNGValidateAttributeList:
8955 * @ctxt: a Relax-NG validation context
8956 * @define: the list of definition to verify
8957 *
8958 * Validate the given node against the list of attribute definitions
8959 *
8960 * Returns 0 if the validation succeeded or an error code.
8961 */
8962static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008963xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8964 xmlRelaxNGDefinePtr defines)
8965{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008966 int ret = 0, res;
8967 int needmore = 0;
8968 xmlRelaxNGDefinePtr cur;
8969
8970 cur = defines;
8971 while (cur != NULL) {
8972 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008973 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8974 ret = -1;
8975 } else
8976 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008977 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008978 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008979 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00008980 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008981 cur = defines;
8982 while (cur != NULL) {
8983 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008984 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8985 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8986 if (res < 0)
8987 ret = -1;
8988 } else {
8989 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8990 return (-1);
8991 }
8992 if (res == -1) /* continues on -2 */
8993 break;
8994 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008995 cur = cur->next;
8996 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008997
8998 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008999}
9000
9001/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009002 * xmlRelaxNGNodeMatchesList:
9003 * @node: the node
9004 * @list: a NULL terminated array of definitions
9005 *
9006 * Check if a node can be matched by one of the definitions
9007 *
9008 * Returns 1 if matches 0 otherwise
9009 */
9010static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009011xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9012{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009013 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009014 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009015
9016 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009017 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009018
9019 cur = list[i++];
9020 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009021 if ((node->type == XML_ELEMENT_NODE) &&
9022 (cur->type == XML_RELAXNG_ELEMENT)) {
9023 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9024 if (tmp == 1)
9025 return (1);
9026 } else if (((node->type == XML_TEXT_NODE) ||
9027 (node->type == XML_CDATA_SECTION_NODE)) &&
9028 (cur->type == XML_RELAXNG_TEXT)) {
9029 return (1);
9030 }
9031 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009032 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009033 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009034}
9035
9036/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009037 * xmlRelaxNGValidateInterleave:
9038 * @ctxt: a Relax-NG validation context
9039 * @define: the definition to verify
9040 *
9041 * Validate an interleave definition for a node.
9042 *
9043 * Returns 0 if the validation succeeded or an error code.
9044 */
9045static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009046xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9047 xmlRelaxNGDefinePtr define)
9048{
William M. Brack779af002003-08-01 15:55:39 +00009049 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009050 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009051 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009052
9053 xmlRelaxNGValidStatePtr oldstate;
9054 xmlRelaxNGPartitionPtr partitions;
9055 xmlRelaxNGInterleaveGroupPtr group = NULL;
9056 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9057 xmlNodePtr *list = NULL, *lasts = NULL;
9058
9059 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009060 partitions = (xmlRelaxNGPartitionPtr) define->data;
9061 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009062 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009063 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9064 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009065 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009066 /*
9067 * Optimizations for MIXED
9068 */
9069 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009070 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009071 ctxt->flags |= FLAGS_MIXED_CONTENT;
9072 if (nbgroups == 2) {
9073 /*
9074 * this is a pure <mixed> case
9075 */
9076 if (ctxt->state != NULL)
9077 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9078 ctxt->state->seq);
9079 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9080 ret = xmlRelaxNGValidateDefinition(ctxt,
9081 partitions->groups[1]->
9082 rule);
9083 else
9084 ret = xmlRelaxNGValidateDefinition(ctxt,
9085 partitions->groups[0]->
9086 rule);
9087 if (ret == 0) {
9088 if (ctxt->state != NULL)
9089 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9090 ctxt->state->
9091 seq);
9092 }
9093 ctxt->flags = oldflags;
9094 return (ret);
9095 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009096 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009097
9098 /*
9099 * Build arrays to store the first and last node of the chain
9100 * pertaining to each group
9101 */
9102 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9103 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009104 xmlRngVErrMemory(ctxt, "validating\n");
9105 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009106 }
9107 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9108 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9109 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009110 xmlRngVErrMemory(ctxt, "validating\n");
9111 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009112 }
9113 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9114
9115 /*
9116 * Walk the sequence of children finding the right group and
9117 * sorting them in sequences.
9118 */
9119 cur = ctxt->state->seq;
9120 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9121 start = cur;
9122 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009123 ctxt->state->seq = cur;
9124 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009125 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009126 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009127
Daniel Veillard4c004142003-10-07 11:33:24 +00009128 if ((cur->type == XML_TEXT_NODE) ||
9129 (cur->type == XML_CDATA_SECTION_NODE)) {
9130 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9131 NULL);
9132 } else if (cur->type == XML_ELEMENT_NODE) {
9133 if (cur->ns != NULL) {
9134 tmp = xmlHashLookup2(partitions->triage, cur->name,
9135 cur->ns->href);
9136 if (tmp == NULL)
9137 tmp = xmlHashLookup2(partitions->triage,
9138 BAD_CAST "#any",
9139 cur->ns->href);
9140 } else
9141 tmp =
9142 xmlHashLookup2(partitions->triage, cur->name,
9143 NULL);
9144 if (tmp == NULL)
9145 tmp =
9146 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9147 NULL);
9148 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009149
Daniel Veillard4c004142003-10-07 11:33:24 +00009150 if (tmp == NULL) {
9151 i = nbgroups;
9152 } else {
9153 i = ((long) tmp) - 1;
9154 if (partitions->flags & IS_NEEDCHECK) {
9155 group = partitions->groups[i];
9156 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9157 i = nbgroups;
9158 }
9159 }
9160 } else {
9161 for (i = 0; i < nbgroups; i++) {
9162 group = partitions->groups[i];
9163 if (group == NULL)
9164 continue;
9165 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9166 break;
9167 }
9168 }
9169 /*
9170 * We break as soon as an element not matched is found
9171 */
9172 if (i >= nbgroups) {
9173 break;
9174 }
9175 if (lasts[i] != NULL) {
9176 lasts[i]->next = cur;
9177 lasts[i] = cur;
9178 } else {
9179 list[i] = cur;
9180 lasts[i] = cur;
9181 }
9182 if (cur->next != NULL)
9183 lastchg = cur->next;
9184 else
9185 lastchg = cur;
9186 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009187 }
9188 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009189 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9190 ret = -1;
9191 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009192 }
9193 lastelem = cur;
9194 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009195 for (i = 0; i < nbgroups; i++) {
9196 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9197 group = partitions->groups[i];
9198 if (lasts[i] != NULL) {
9199 last = lasts[i]->next;
9200 lasts[i]->next = NULL;
9201 }
9202 ctxt->state->seq = list[i];
9203 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9204 if (ret != 0)
9205 break;
9206 if (ctxt->state != NULL) {
9207 cur = ctxt->state->seq;
9208 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9209 xmlRelaxNGFreeValidState(ctxt, oldstate);
9210 oldstate = ctxt->state;
9211 ctxt->state = NULL;
9212 if (cur != NULL) {
9213 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9214 ret = -1;
9215 ctxt->state = oldstate;
9216 goto done;
9217 }
9218 } else if (ctxt->states != NULL) {
9219 int j;
9220 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009221
Daniel Veillard4c004142003-10-07 11:33:24 +00009222 for (j = 0; j < ctxt->states->nbState; j++) {
9223 cur = ctxt->states->tabState[j]->seq;
9224 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9225 if (cur == NULL) {
9226 found = 1;
9227 break;
9228 }
9229 }
9230 if (ctxt->states->nbState > 0) {
9231 xmlRelaxNGFreeValidState(ctxt, oldstate);
9232 oldstate =
9233 ctxt->states->tabState[ctxt->states->nbState - 1];
9234 }
9235 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9236 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9237 }
9238 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9239 ctxt->states = NULL;
9240 if (found == 0) {
9241 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9242 ret = -1;
9243 ctxt->state = oldstate;
9244 goto done;
9245 }
9246 } else {
9247 ret = -1;
9248 break;
9249 }
9250 if (lasts[i] != NULL) {
9251 lasts[i]->next = last;
9252 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009253 }
9254 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009255 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009256 ctxt->state = oldstate;
9257 ctxt->state->seq = lastelem;
9258 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009259 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9260 ret = -1;
9261 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009262 }
9263
Daniel Veillard4c004142003-10-07 11:33:24 +00009264 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009265 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009266 /*
9267 * builds the next links chain from the prev one
9268 */
9269 cur = lastchg;
9270 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009271 if ((cur == start) || (cur->prev == NULL))
9272 break;
9273 cur->prev->next = cur;
9274 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009275 }
9276 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009277 if (ctxt->errNr > errNr)
9278 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009279 }
9280
9281 xmlFree(list);
9282 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009283 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009284}
9285
9286/**
9287 * xmlRelaxNGValidateDefinitionList:
9288 * @ctxt: a Relax-NG validation context
9289 * @define: the list of definition to verify
9290 *
9291 * Validate the given node content against the (list) of definitions
9292 *
9293 * Returns 0 if the validation succeeded or an error code.
9294 */
9295static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009296xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9297 xmlRelaxNGDefinePtr defines)
9298{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009299 int ret = 0, res;
9300
9301
Daniel Veillard952379b2003-03-17 15:37:12 +00009302 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009303 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9304 BAD_CAST "NULL definition list");
9305 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009306 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009307 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009308 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9309 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9310 if (res < 0)
9311 ret = -1;
9312 } else {
9313 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9314 return (-1);
9315 }
9316 if (res == -1) /* continues on -2 */
9317 break;
9318 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009319 }
9320
Daniel Veillard4c004142003-10-07 11:33:24 +00009321 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009322}
9323
9324/**
9325 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009326 * @ctxt: a Relax-NG validation context
9327 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009328 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009329 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009330 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009331 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009332 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009333 */
9334static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009335xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9336 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9337{
Daniel Veillard580ced82003-03-21 21:22:48 +00009338 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009339
Daniel Veillardfd573f12003-03-16 17:52:32 +00009340 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009341 if (!xmlStrEqual(elem->name, define->name)) {
9342 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9343 return (0);
9344 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009345 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009346 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009347 if (elem->ns == NULL) {
9348 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9349 return (0);
9350 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9351 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9352 elem->name, define->ns);
9353 return (0);
9354 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009355 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009356 (define->name == NULL)) {
9357 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9358 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009359 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009360 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9361 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009362 }
9363
9364 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009365 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009366
9367 define = define->nameClass;
9368 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009369 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009370
Daniel Veillard4c004142003-10-07 11:33:24 +00009371 if (ctxt != NULL) {
9372 oldflags = ctxt->flags;
9373 ctxt->flags |= FLAGS_IGNORABLE;
9374 }
9375
9376 list = define->content;
9377 while (list != NULL) {
9378 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9379 if (ret == 1) {
9380 if (ctxt != NULL)
9381 ctxt->flags = oldflags;
9382 return (0);
9383 }
9384 if (ret < 0) {
9385 if (ctxt != NULL)
9386 ctxt->flags = oldflags;
9387 return (ret);
9388 }
9389 list = list->next;
9390 }
9391 ret = 1;
9392 if (ctxt != NULL) {
9393 ctxt->flags = oldflags;
9394 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009395 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009396 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009397
Daniel Veillard4c004142003-10-07 11:33:24 +00009398 if (ctxt != NULL) {
9399 oldflags = ctxt->flags;
9400 ctxt->flags |= FLAGS_IGNORABLE;
9401 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009402
Daniel Veillard4c004142003-10-07 11:33:24 +00009403 list = define->nameClass;
9404 while (list != NULL) {
9405 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9406 if (ret == 1) {
9407 if (ctxt != NULL)
9408 ctxt->flags = oldflags;
9409 return (1);
9410 }
9411 if (ret < 0) {
9412 if (ctxt != NULL)
9413 ctxt->flags = oldflags;
9414 return (ret);
9415 }
9416 list = list->next;
9417 }
9418 if (ctxt != NULL) {
9419 if (ret != 0) {
9420 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9421 xmlRelaxNGDumpValidError(ctxt);
9422 } else {
9423 if (ctxt->errNr > 0)
9424 xmlRelaxNGPopErrors(ctxt, 0);
9425 }
9426 }
9427 ret = 0;
9428 if (ctxt != NULL) {
9429 ctxt->flags = oldflags;
9430 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009431 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009432 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009433 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009434 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009435}
9436
9437/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009438 * xmlRelaxNGBestState:
9439 * @ctxt: a Relax-NG validation context
9440 *
9441 * Find the "best" state in the ctxt->states list of states to report
9442 * errors about. I.e. a state with no element left in the child list
9443 * or the one with the less attributes left.
9444 * This is called only if a falidation error was detected
9445 *
9446 * Returns the index of the "best" state or -1 in case of error
9447 */
9448static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009449xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9450{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009451 xmlRelaxNGValidStatePtr state;
9452 int i, tmp;
9453 int best = -1;
9454 int value = 1000000;
9455
9456 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9457 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009458 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009459
Daniel Veillard4c004142003-10-07 11:33:24 +00009460 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009461 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009462 if (state == NULL)
9463 continue;
9464 if (state->seq != NULL) {
9465 if ((best == -1) || (value > 100000)) {
9466 value = 100000;
9467 best = i;
9468 }
9469 } else {
9470 tmp = state->nbAttrLeft;
9471 if ((best == -1) || (value > tmp)) {
9472 value = tmp;
9473 best = i;
9474 }
9475 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009476 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009477 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009478}
9479
9480/**
9481 * xmlRelaxNGLogBestError:
9482 * @ctxt: a Relax-NG validation context
9483 *
9484 * Find the "best" state in the ctxt->states list of states to report
9485 * errors about and log it.
9486 */
9487static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009488xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9489{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009490 int best;
9491
9492 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9493 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009494 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009495
9496 best = xmlRelaxNGBestState(ctxt);
9497 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009498 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009499
Daniel Veillard4c004142003-10-07 11:33:24 +00009500 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009501 }
9502}
9503
9504/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009505 * xmlRelaxNGValidateElementEnd:
9506 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009507 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009508 *
9509 * Validate the end of the element, implements check that
9510 * there is nothing left not consumed in the element content
9511 * or in the attribute list.
9512 *
9513 * Returns 0 if the validation succeeded or an error code.
9514 */
9515static int
William M. Brack272693c2003-11-14 16:20:34 +00009516xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009517{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009518 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009519 xmlRelaxNGValidStatePtr state;
9520
9521 state = ctxt->state;
9522 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009523 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9524 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009525 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009526 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9527 state->node->name, state->seq->name);
9528 }
9529 return (-1);
9530 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009531 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009532 for (i = 0; i < state->nbAttrs; i++) {
9533 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009534 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009535 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9536 state->attrs[i]->name, state->node->name);
9537 }
9538 return (-1 - i);
9539 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009540 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009541 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009542}
9543
9544/**
9545 * xmlRelaxNGValidateState:
9546 * @ctxt: a Relax-NG validation context
9547 * @define: the definition to verify
9548 *
9549 * Validate the current state against the definition
9550 *
9551 * Returns 0 if the validation succeeded or an error code.
9552 */
9553static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009554xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9555 xmlRelaxNGDefinePtr define)
9556{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009557 xmlNodePtr node;
9558 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009559 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009560
9561 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009562 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9563 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009564 }
9565
9566 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009567 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009568 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009569 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009570 }
9571#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009572 for (i = 0; i < ctxt->depth; i++)
9573 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009574 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009575 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009576 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009577 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009578 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009579 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009580 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009581 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009582#endif
9583 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009584 switch (define->type) {
9585 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009586 node = xmlRelaxNGSkipIgnored(ctxt, node);
9587 ret = 0;
9588 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009589 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009590 ret = -1;
9591 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009592 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009593 while ((node != NULL) &&
9594 ((node->type == XML_TEXT_NODE) ||
9595 (node->type == XML_COMMENT_NODE) ||
9596 (node->type == XML_PI_NODE) ||
9597 (node->type == XML_CDATA_SECTION_NODE)))
9598 node = node->next;
9599 ctxt->state->seq = node;
9600 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009601 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009602 errNr = ctxt->errNr;
9603 node = xmlRelaxNGSkipIgnored(ctxt, node);
9604 if (node == NULL) {
9605 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9606 ret = -1;
9607 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9608 xmlRelaxNGDumpValidError(ctxt);
9609 break;
9610 }
9611 if (node->type != XML_ELEMENT_NODE) {
9612 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9613 ret = -1;
9614 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9615 xmlRelaxNGDumpValidError(ctxt);
9616 break;
9617 }
9618 /*
9619 * This node was already validated successfully against
9620 * this definition.
9621 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009622 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009623 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9624 if (ctxt->errNr > errNr)
9625 xmlRelaxNGPopErrors(ctxt, errNr);
9626 if (ctxt->errNr != 0) {
9627 while ((ctxt->err != NULL) &&
9628 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9629 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9630 ||
9631 ((ctxt->err->err ==
9632 XML_RELAXNG_ERR_ELEMEXTRANS)
9633 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9634 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9635 || (ctxt->err->err ==
9636 XML_RELAXNG_ERR_NOTELEM)))
9637 xmlRelaxNGValidErrorPop(ctxt);
9638 }
9639 break;
9640 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009641
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009642 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9643 if (ret <= 0) {
9644 ret = -1;
9645 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9646 xmlRelaxNGDumpValidError(ctxt);
9647 break;
9648 }
9649 ret = 0;
9650 if (ctxt->errNr != 0) {
9651 if (ctxt->errNr > errNr)
9652 xmlRelaxNGPopErrors(ctxt, errNr);
9653 while ((ctxt->err != NULL) &&
9654 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9655 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9656 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9657 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9658 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9659 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9660 xmlRelaxNGValidErrorPop(ctxt);
9661 }
9662 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009663
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009664 oldflags = ctxt->flags;
9665 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9666 ctxt->flags -= FLAGS_MIXED_CONTENT;
9667 }
9668 state = xmlRelaxNGNewValidState(ctxt, node);
9669 if (state == NULL) {
9670 ret = -1;
9671 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9672 xmlRelaxNGDumpValidError(ctxt);
9673 break;
9674 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009675
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009676 oldstate = ctxt->state;
9677 ctxt->state = state;
9678 if (define->attrs != NULL) {
9679 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9680 if (tmp != 0) {
9681 ret = -1;
9682 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9683 }
9684 }
9685 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009686 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9687 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9688 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009689
Daniel Veillard4c004142003-10-07 11:33:24 +00009690 nstate = xmlRelaxNGNewValidState(ctxt, node);
9691 ctxt->state = nstate;
9692 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009693
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009694 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9695 define->contModel,
9696 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009697 nseq = ctxt->state->seq;
9698 ctxt->state = tmpstate;
9699 ctxt->states = tmpstates;
9700 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009701
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009702#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009703 xmlGenericError(xmlGenericErrorContext,
9704 "Validating content of '%s' : %d\n",
9705 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009706#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009707 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009708 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009709
9710 if (ctxt->states != NULL) {
9711 tmp = -1;
9712
Daniel Veillardce192eb2003-04-16 15:58:05 +00009713 for (i = 0; i < ctxt->states->nbState; i++) {
9714 state = ctxt->states->tabState[i];
9715 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009716 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009717
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009718 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009719 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009720 break;
9721 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009722 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009723 if (tmp != 0) {
9724 /*
9725 * validation error, log the message for the "best" one
9726 */
9727 ctxt->flags |= FLAGS_IGNORABLE;
9728 xmlRelaxNGLogBestError(ctxt);
9729 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009730 for (i = 0; i < ctxt->states->nbState; i++) {
9731 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009732 ctxt->states->
9733 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009734 }
9735 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9736 ctxt->flags = oldflags;
9737 ctxt->states = NULL;
9738 if ((ret == 0) && (tmp == -1))
9739 ret = -1;
9740 } else {
9741 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009742 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009743 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009744 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009745 xmlRelaxNGFreeValidState(ctxt, state);
9746 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009747 } else {
9748 if (define->content != NULL) {
9749 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009750 define->
9751 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009752 if (tmp != 0) {
9753 ret = -1;
9754 if (ctxt->state == NULL) {
9755 ctxt->state = oldstate;
9756 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9757 node->name);
9758 ctxt->state = NULL;
9759 } else {
9760 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9761 node->name);
9762 }
9763
9764 }
9765 }
9766 if (ctxt->states != NULL) {
9767 tmp = -1;
9768
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009769 for (i = 0; i < ctxt->states->nbState; i++) {
9770 state = ctxt->states->tabState[i];
9771 ctxt->state = state;
9772
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009773 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009774 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009775 break;
9776 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009777 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009778 if (tmp != 0) {
9779 /*
9780 * validation error, log the message for the "best" one
9781 */
9782 ctxt->flags |= FLAGS_IGNORABLE;
9783 xmlRelaxNGLogBestError(ctxt);
9784 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009785 for (i = 0; i < ctxt->states->nbState; i++) {
9786 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009787 ctxt->states->
9788 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009789 }
9790 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9791 ctxt->flags = oldflags;
9792 ctxt->states = NULL;
9793 if ((ret == 0) && (tmp == -1))
9794 ret = -1;
9795 } else {
9796 state = ctxt->state;
9797 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009798 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009799 xmlRelaxNGFreeValidState(ctxt, state);
9800 }
9801 }
9802 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009803 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009804 }
9805 ctxt->flags = oldflags;
9806 ctxt->state = oldstate;
9807 if (oldstate != NULL)
9808 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9809 if (ret != 0) {
9810 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9811 xmlRelaxNGDumpValidError(ctxt);
9812 ret = 0;
9813 } else {
9814 ret = -2;
9815 }
9816 } else {
9817 if (ctxt->errNr > errNr)
9818 xmlRelaxNGPopErrors(ctxt, errNr);
9819 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009820
9821#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009822 xmlGenericError(xmlGenericErrorContext,
9823 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9824 node->name, ret);
9825 if (oldstate == NULL)
9826 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9827 else if (oldstate->seq == NULL)
9828 xmlGenericError(xmlGenericErrorContext, ": done\n");
9829 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9830 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9831 oldstate->seq->name);
9832 else
9833 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9834 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009835#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009836 break;
9837 case XML_RELAXNG_OPTIONAL:{
9838 errNr = ctxt->errNr;
9839 oldflags = ctxt->flags;
9840 ctxt->flags |= FLAGS_IGNORABLE;
9841 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9842 ret =
9843 xmlRelaxNGValidateDefinitionList(ctxt,
9844 define->content);
9845 if (ret != 0) {
9846 if (ctxt->state != NULL)
9847 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9848 ctxt->state = oldstate;
9849 ctxt->flags = oldflags;
9850 ret = 0;
9851 if (ctxt->errNr > errNr)
9852 xmlRelaxNGPopErrors(ctxt, errNr);
9853 break;
9854 }
9855 if (ctxt->states != NULL) {
9856 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9857 } else {
9858 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9859 if (ctxt->states == NULL) {
9860 xmlRelaxNGFreeValidState(ctxt, oldstate);
9861 ctxt->flags = oldflags;
9862 ret = -1;
9863 if (ctxt->errNr > errNr)
9864 xmlRelaxNGPopErrors(ctxt, errNr);
9865 break;
9866 }
9867 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9868 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9869 ctxt->state = NULL;
9870 }
9871 ctxt->flags = oldflags;
9872 ret = 0;
9873 if (ctxt->errNr > errNr)
9874 xmlRelaxNGPopErrors(ctxt, errNr);
9875 break;
9876 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009877 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009878 errNr = ctxt->errNr;
9879 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9880 if (ret != 0) {
9881 break;
9882 }
9883 if (ctxt->errNr > errNr)
9884 xmlRelaxNGPopErrors(ctxt, errNr);
9885 /* no break on purpose */
9886 case XML_RELAXNG_ZEROORMORE:{
9887 int progress;
9888 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9889 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009890
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009891 errNr = ctxt->errNr;
9892 res = xmlRelaxNGNewStates(ctxt, 1);
9893 if (res == NULL) {
9894 ret = -1;
9895 break;
9896 }
9897 /*
9898 * All the input states are also exit states
9899 */
9900 if (ctxt->state != NULL) {
9901 xmlRelaxNGAddStates(ctxt, res,
9902 xmlRelaxNGCopyValidState(ctxt,
9903 ctxt->
9904 state));
9905 } else {
9906 for (j = 0; j < ctxt->states->nbState; j++) {
9907 xmlRelaxNGAddStates(ctxt, res,
9908 xmlRelaxNGCopyValidState(ctxt,
9909 ctxt->
9910 states->
9911 tabState
9912 [j]));
9913 }
9914 }
9915 oldflags = ctxt->flags;
9916 ctxt->flags |= FLAGS_IGNORABLE;
9917 do {
9918 progress = 0;
9919 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009920
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009921 if (ctxt->states != NULL) {
9922 states = ctxt->states;
9923 for (i = 0; i < states->nbState; i++) {
9924 ctxt->state = states->tabState[i];
9925 ctxt->states = NULL;
9926 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9927 define->
9928 content);
9929 if (ret == 0) {
9930 if (ctxt->state != NULL) {
9931 tmp = xmlRelaxNGAddStates(ctxt, res,
9932 ctxt->state);
9933 ctxt->state = NULL;
9934 if (tmp == 1)
9935 progress = 1;
9936 } else if (ctxt->states != NULL) {
9937 for (j = 0; j < ctxt->states->nbState;
9938 j++) {
9939 tmp =
9940 xmlRelaxNGAddStates(ctxt, res,
9941 ctxt->
9942 states->
9943 tabState
9944 [j]);
9945 if (tmp == 1)
9946 progress = 1;
9947 }
9948 xmlRelaxNGFreeStates(ctxt,
9949 ctxt->states);
9950 ctxt->states = NULL;
9951 }
9952 } else {
9953 if (ctxt->state != NULL) {
9954 xmlRelaxNGFreeValidState(ctxt,
9955 ctxt->state);
9956 ctxt->state = NULL;
9957 }
9958 }
9959 }
9960 } else {
9961 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9962 define->
9963 content);
9964 if (ret != 0) {
9965 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9966 ctxt->state = NULL;
9967 } else {
9968 base = res->nbState;
9969 if (ctxt->state != NULL) {
9970 tmp = xmlRelaxNGAddStates(ctxt, res,
9971 ctxt->state);
9972 ctxt->state = NULL;
9973 if (tmp == 1)
9974 progress = 1;
9975 } else if (ctxt->states != NULL) {
9976 for (j = 0; j < ctxt->states->nbState; j++) {
9977 tmp = xmlRelaxNGAddStates(ctxt, res,
9978 ctxt->
9979 states->
9980 tabState[j]);
9981 if (tmp == 1)
9982 progress = 1;
9983 }
9984 if (states == NULL) {
9985 states = ctxt->states;
9986 } else {
9987 xmlRelaxNGFreeStates(ctxt,
9988 ctxt->states);
9989 }
9990 ctxt->states = NULL;
9991 }
9992 }
9993 }
9994 if (progress) {
9995 /*
9996 * Collect all the new nodes added at that step
9997 * and make them the new node set
9998 */
9999 if (res->nbState - base == 1) {
10000 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10001 res->
10002 tabState
10003 [base]);
10004 } else {
10005 if (states == NULL) {
10006 xmlRelaxNGNewStates(ctxt,
10007 res->nbState - base);
10008 }
10009 states->nbState = 0;
10010 for (i = base; i < res->nbState; i++)
10011 xmlRelaxNGAddStates(ctxt, states,
10012 xmlRelaxNGCopyValidState
10013 (ctxt,
10014 res->tabState[i]));
10015 ctxt->states = states;
10016 }
10017 }
10018 } while (progress == 1);
10019 if (states != NULL) {
10020 xmlRelaxNGFreeStates(ctxt, states);
10021 }
10022 ctxt->states = res;
10023 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010024#if 0
10025 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010026 * errors may have to be propagated back...
10027 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010028 if (ctxt->errNr > errNr)
10029 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010030#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010031 ret = 0;
10032 break;
10033 }
10034 case XML_RELAXNG_CHOICE:{
10035 xmlRelaxNGDefinePtr list = NULL;
10036 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010037
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010038 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010039
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010040 errNr = ctxt->errNr;
10041 if ((define->dflags & IS_TRIABLE)
10042 && (define->data != NULL)) {
10043 xmlHashTablePtr triage =
10044 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010045
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010046 /*
10047 * Something we can optimize cleanly there is only one
10048 * possble branch out !
10049 */
10050 if (node == NULL) {
10051 ret = -1;
10052 break;
10053 }
10054 if ((node->type == XML_TEXT_NODE) ||
10055 (node->type == XML_CDATA_SECTION_NODE)) {
10056 list =
10057 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10058 } else if (node->type == XML_ELEMENT_NODE) {
10059 if (node->ns != NULL) {
10060 list = xmlHashLookup2(triage, node->name,
10061 node->ns->href);
10062 if (list == NULL)
10063 list =
10064 xmlHashLookup2(triage, BAD_CAST "#any",
10065 node->ns->href);
10066 } else
10067 list =
10068 xmlHashLookup2(triage, node->name, NULL);
10069 if (list == NULL)
10070 list =
10071 xmlHashLookup2(triage, BAD_CAST "#any",
10072 NULL);
10073 }
10074 if (list == NULL) {
10075 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010076 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010077 break;
10078 }
10079 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10080 if (ret == 0) {
10081 }
10082 break;
10083 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010084
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010085 list = define->content;
10086 oldflags = ctxt->flags;
10087 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010088
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010089 while (list != NULL) {
10090 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10091 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10092 if (ret == 0) {
10093 if (states == NULL) {
10094 states = xmlRelaxNGNewStates(ctxt, 1);
10095 }
10096 if (ctxt->state != NULL) {
10097 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10098 } else if (ctxt->states != NULL) {
10099 for (i = 0; i < ctxt->states->nbState; i++) {
10100 xmlRelaxNGAddStates(ctxt, states,
10101 ctxt->states->
10102 tabState[i]);
10103 }
10104 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10105 ctxt->states = NULL;
10106 }
10107 } else {
10108 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10109 }
10110 ctxt->state = oldstate;
10111 list = list->next;
10112 }
10113 if (states != NULL) {
10114 xmlRelaxNGFreeValidState(ctxt, oldstate);
10115 ctxt->states = states;
10116 ctxt->state = NULL;
10117 ret = 0;
10118 } else {
10119 ctxt->states = NULL;
10120 }
10121 ctxt->flags = oldflags;
10122 if (ret != 0) {
10123 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10124 xmlRelaxNGDumpValidError(ctxt);
10125 }
10126 } else {
10127 if (ctxt->errNr > errNr)
10128 xmlRelaxNGPopErrors(ctxt, errNr);
10129 }
10130 break;
10131 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010132 case XML_RELAXNG_DEF:
10133 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010134 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10135 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010136 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010137 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10138 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010139 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010140 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10141 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010142 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010143 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010144 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010145 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010146 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010147 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10148 break;
10149 case XML_RELAXNG_DATATYPE:{
10150 xmlNodePtr child;
10151 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010152
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010153 child = node;
10154 while (child != NULL) {
10155 if (child->type == XML_ELEMENT_NODE) {
10156 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10157 node->parent->name);
10158 ret = -1;
10159 break;
10160 } else if ((child->type == XML_TEXT_NODE) ||
10161 (child->type == XML_CDATA_SECTION_NODE)) {
10162 content = xmlStrcat(content, child->content);
10163 }
10164 /* TODO: handle entities ... */
10165 child = child->next;
10166 }
10167 if (ret == -1) {
10168 if (content != NULL)
10169 xmlFree(content);
10170 break;
10171 }
10172 if (content == NULL) {
10173 content = xmlStrdup(BAD_CAST "");
10174 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010175 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010176 ret = -1;
10177 break;
10178 }
10179 }
10180 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10181 ctxt->state->seq);
10182 if (ret == -1) {
10183 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10184 } else if (ret == 0) {
10185 ctxt->state->seq = NULL;
10186 }
10187 if (content != NULL)
10188 xmlFree(content);
10189 break;
10190 }
10191 case XML_RELAXNG_VALUE:{
10192 xmlChar *content = NULL;
10193 xmlChar *oldvalue;
10194 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010195
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010196 child = node;
10197 while (child != NULL) {
10198 if (child->type == XML_ELEMENT_NODE) {
10199 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10200 node->parent->name);
10201 ret = -1;
10202 break;
10203 } else if ((child->type == XML_TEXT_NODE) ||
10204 (child->type == XML_CDATA_SECTION_NODE)) {
10205 content = xmlStrcat(content, child->content);
10206 }
10207 /* TODO: handle entities ... */
10208 child = child->next;
10209 }
10210 if (ret == -1) {
10211 if (content != NULL)
10212 xmlFree(content);
10213 break;
10214 }
10215 if (content == NULL) {
10216 content = xmlStrdup(BAD_CAST "");
10217 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010218 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010219 ret = -1;
10220 break;
10221 }
10222 }
10223 oldvalue = ctxt->state->value;
10224 ctxt->state->value = content;
10225 ret = xmlRelaxNGValidateValue(ctxt, define);
10226 ctxt->state->value = oldvalue;
10227 if (ret == -1) {
10228 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10229 } else if (ret == 0) {
10230 ctxt->state->seq = NULL;
10231 }
10232 if (content != NULL)
10233 xmlFree(content);
10234 break;
10235 }
10236 case XML_RELAXNG_LIST:{
10237 xmlChar *content;
10238 xmlNodePtr child;
10239 xmlChar *oldvalue, *oldendvalue;
10240 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010241
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010242 /*
10243 * Make sure it's only text nodes
10244 */
10245
10246 content = NULL;
10247 child = node;
10248 while (child != NULL) {
10249 if (child->type == XML_ELEMENT_NODE) {
10250 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10251 node->parent->name);
10252 ret = -1;
10253 break;
10254 } else if ((child->type == XML_TEXT_NODE) ||
10255 (child->type == XML_CDATA_SECTION_NODE)) {
10256 content = xmlStrcat(content, child->content);
10257 }
10258 /* TODO: handle entities ... */
10259 child = child->next;
10260 }
10261 if (ret == -1) {
10262 if (content != NULL)
10263 xmlFree(content);
10264 break;
10265 }
10266 if (content == NULL) {
10267 content = xmlStrdup(BAD_CAST "");
10268 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010269 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010270 ret = -1;
10271 break;
10272 }
10273 }
10274 len = xmlStrlen(content);
10275 oldvalue = ctxt->state->value;
10276 oldendvalue = ctxt->state->endvalue;
10277 ctxt->state->value = content;
10278 ctxt->state->endvalue = content + len;
10279 ret = xmlRelaxNGValidateValue(ctxt, define);
10280 ctxt->state->value = oldvalue;
10281 ctxt->state->endvalue = oldendvalue;
10282 if (ret == -1) {
10283 VALID_ERR(XML_RELAXNG_ERR_LIST);
10284 } else if ((ret == 0) && (node != NULL)) {
10285 ctxt->state->seq = node->next;
10286 }
10287 if (content != NULL)
10288 xmlFree(content);
10289 break;
10290 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010291 case XML_RELAXNG_EXCEPT:
10292 case XML_RELAXNG_PARAM:
10293 TODO ret = -1;
10294 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010295 }
10296 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010297#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010298 for (i = 0; i < ctxt->depth; i++)
10299 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010300 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010301 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010302 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010303 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010304 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010305 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010306 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010307 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010308#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010309 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010310}
10311
10312/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010313 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010314 * @ctxt: a Relax-NG validation context
10315 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010316 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010317 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010318 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010319 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010320 */
10321static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010322xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10323 xmlRelaxNGDefinePtr define)
10324{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010325 xmlRelaxNGStatesPtr states, res;
10326 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010327
Daniel Veillardfd573f12003-03-16 17:52:32 +000010328 /*
10329 * We should NOT have both ctxt->state and ctxt->states
10330 */
10331 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010332 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10333 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010334 }
10335
10336 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010337 if (ctxt->states != NULL) {
10338 ctxt->state = ctxt->states->tabState[0];
10339 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10340 ctxt->states = NULL;
10341 }
10342 ret = xmlRelaxNGValidateState(ctxt, define);
10343 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10344 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10345 ctxt->state = NULL;
10346 }
10347 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10348 ctxt->state = ctxt->states->tabState[0];
10349 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10350 ctxt->states = NULL;
10351 }
10352 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010353 }
10354
10355 states = ctxt->states;
10356 ctxt->states = NULL;
10357 res = NULL;
10358 j = 0;
10359 oldflags = ctxt->flags;
10360 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010361 for (i = 0; i < states->nbState; i++) {
10362 ctxt->state = states->tabState[i];
10363 ctxt->states = NULL;
10364 ret = xmlRelaxNGValidateState(ctxt, define);
10365 /*
10366 * We should NOT have both ctxt->state and ctxt->states
10367 */
10368 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10369 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10370 ctxt->state = NULL;
10371 }
10372 if (ret == 0) {
10373 if (ctxt->states == NULL) {
10374 if (res != NULL) {
10375 /* add the state to the container */
10376 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10377 ctxt->state = NULL;
10378 } else {
10379 /* add the state directly in states */
10380 states->tabState[j++] = ctxt->state;
10381 ctxt->state = NULL;
10382 }
10383 } else {
10384 if (res == NULL) {
10385 /* make it the new container and copy other results */
10386 res = ctxt->states;
10387 ctxt->states = NULL;
10388 for (k = 0; k < j; k++)
10389 xmlRelaxNGAddStates(ctxt, res,
10390 states->tabState[k]);
10391 } else {
10392 /* add all the new results to res and reff the container */
10393 for (k = 0; k < ctxt->states->nbState; k++)
10394 xmlRelaxNGAddStates(ctxt, res,
10395 ctxt->states->tabState[k]);
10396 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10397 ctxt->states = NULL;
10398 }
10399 }
10400 } else {
10401 if (ctxt->state != NULL) {
10402 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10403 ctxt->state = NULL;
10404 } else if (ctxt->states != NULL) {
10405 for (k = 0; k < ctxt->states->nbState; k++)
10406 xmlRelaxNGFreeValidState(ctxt,
10407 ctxt->states->tabState[k]);
10408 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10409 ctxt->states = NULL;
10410 }
10411 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010412 }
10413 ctxt->flags = oldflags;
10414 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010415 xmlRelaxNGFreeStates(ctxt, states);
10416 ctxt->states = res;
10417 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010418 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010419 states->nbState = j;
10420 ctxt->states = states;
10421 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010422 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010423 ctxt->state = states->tabState[0];
10424 xmlRelaxNGFreeStates(ctxt, states);
10425 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010426 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010427 ret = -1;
10428 xmlRelaxNGFreeStates(ctxt, states);
10429 if (ctxt->states != NULL) {
10430 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10431 ctxt->states = NULL;
10432 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010433 }
10434 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010435 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10436 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010437 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010438 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010439}
10440
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010441/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010442 * xmlRelaxNGValidateDocument:
10443 * @ctxt: a Relax-NG validation context
10444 * @doc: the document
10445 *
10446 * Validate the given document
10447 *
10448 * Returns 0 if the validation succeeded or an error code.
10449 */
10450static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010451xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10452{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010453 int ret;
10454 xmlRelaxNGPtr schema;
10455 xmlRelaxNGGrammarPtr grammar;
10456 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010457 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010458
10459 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010460 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010461
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010462 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010463 schema = ctxt->schema;
10464 grammar = schema->topgrammar;
10465 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010466 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10467 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010468 }
10469 state = xmlRelaxNGNewValidState(ctxt, NULL);
10470 ctxt->state = state;
10471 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010472 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010473 state = ctxt->state;
10474 node = state->seq;
10475 node = xmlRelaxNGSkipIgnored(ctxt, node);
10476 if (node != NULL) {
10477 if (ret != -1) {
10478 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10479 ret = -1;
10480 }
10481 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010482 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010483 int i;
10484 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010485
Daniel Veillard4c004142003-10-07 11:33:24 +000010486 for (i = 0; i < ctxt->states->nbState; i++) {
10487 state = ctxt->states->tabState[i];
10488 node = state->seq;
10489 node = xmlRelaxNGSkipIgnored(ctxt, node);
10490 if (node == NULL)
10491 tmp = 0;
10492 xmlRelaxNGFreeValidState(ctxt, state);
10493 }
10494 if (tmp == -1) {
10495 if (ret != -1) {
10496 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10497 ret = -1;
10498 }
10499 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010500 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010501 if (ctxt->state != NULL) {
10502 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010503 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010504 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010505 if (ret != 0)
10506 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010507#ifdef DEBUG
10508 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010509 ctxt->error(ctxt->userData,
10510 "%d Extra error messages left on stack !\n",
10511 ctxt->errNr);
10512 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010513 }
10514#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010515#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010516 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010517 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010518
Daniel Veillard4c004142003-10-07 11:33:24 +000010519 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10520 vctxt.valid = 1;
10521 vctxt.error = ctxt->error;
10522 vctxt.warning = ctxt->warning;
10523 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010524
Daniel Veillard4c004142003-10-07 11:33:24 +000010525 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10526 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010527 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010528#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010529 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010530 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010531
Daniel Veillard4c004142003-10-07 11:33:24 +000010532 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010533}
10534
Daniel Veillardfd573f12003-03-16 17:52:32 +000010535/************************************************************************
10536 * *
10537 * Validation interfaces *
10538 * *
10539 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010540
Daniel Veillard6eadf632003-01-23 18:29:16 +000010541/**
10542 * xmlRelaxNGNewValidCtxt:
10543 * @schema: a precompiled XML RelaxNGs
10544 *
10545 * Create an XML RelaxNGs validation context based on the given schema
10546 *
10547 * Returns the validation context or NULL in case of error
10548 */
10549xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010550xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10551{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010552 xmlRelaxNGValidCtxtPtr ret;
10553
10554 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10555 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010556 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010557 return (NULL);
10558 }
10559 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10560 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010561 ret->error = xmlGenericError;
10562 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010563 ret->errNr = 0;
10564 ret->errMax = 0;
10565 ret->err = NULL;
10566 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010567 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010568 ret->states = NULL;
10569 ret->freeState = NULL;
10570 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010571 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010572 return (ret);
10573}
10574
10575/**
10576 * xmlRelaxNGFreeValidCtxt:
10577 * @ctxt: the schema validation context
10578 *
10579 * Free the resources associated to the schema validation context
10580 */
10581void
Daniel Veillard4c004142003-10-07 11:33:24 +000010582xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10583{
Daniel Veillard798024a2003-03-19 10:36:09 +000010584 int k;
10585
Daniel Veillard6eadf632003-01-23 18:29:16 +000010586 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010587 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010588 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010589 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010590 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010591 for (k = 0; k < ctxt->freeState->nbState; k++) {
10592 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10593 }
10594 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010595 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010596 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010597 for (k = 0; k < ctxt->freeStatesNr; k++) {
10598 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10599 }
10600 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010601 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010602 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010603 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010604 if (ctxt->elemTab != NULL) {
10605 xmlRegExecCtxtPtr exec;
10606
Daniel Veillard4c004142003-10-07 11:33:24 +000010607 exec = xmlRelaxNGElemPop(ctxt);
10608 while (exec != NULL) {
10609 xmlRegFreeExecCtxt(exec);
10610 exec = xmlRelaxNGElemPop(ctxt);
10611 }
10612 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010613 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010614 xmlFree(ctxt);
10615}
10616
10617/**
10618 * xmlRelaxNGSetValidErrors:
10619 * @ctxt: a Relax-NG validation context
10620 * @err: the error function
10621 * @warn: the warning function
10622 * @ctx: the functions context
10623 *
10624 * Set the error and warning callback informations
10625 */
10626void
10627xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010628 xmlRelaxNGValidityErrorFunc err,
10629 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10630{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010631 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010632 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010633 ctxt->error = err;
10634 ctxt->warning = warn;
10635 ctxt->userData = ctx;
10636}
10637
10638/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010639 * xmlRelaxNGGetValidErrors:
10640 * @ctxt: a Relax-NG validation context
10641 * @err: the error function result
10642 * @warn: the warning function result
10643 * @ctx: the functions context result
10644 *
10645 * Get the error and warning callback informations
10646 *
10647 * Returns -1 in case of error and 0 otherwise
10648 */
10649int
10650xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010651 xmlRelaxNGValidityErrorFunc * err,
10652 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10653{
Daniel Veillard409a8142003-07-18 15:16:57 +000010654 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010655 return (-1);
10656 if (err != NULL)
10657 *err = ctxt->error;
10658 if (warn != NULL)
10659 *warn = ctxt->warning;
10660 if (ctx != NULL)
10661 *ctx = ctxt->userData;
10662 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010663}
10664
10665/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010666 * xmlRelaxNGValidateDoc:
10667 * @ctxt: a Relax-NG validation context
10668 * @doc: a parsed document tree
10669 *
10670 * Validate a document tree in memory.
10671 *
10672 * Returns 0 if the document is valid, a positive error code
10673 * number otherwise and -1 in case of internal or API error.
10674 */
10675int
Daniel Veillard4c004142003-10-07 11:33:24 +000010676xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10677{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010678 int ret;
10679
10680 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010681 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010682
10683 ctxt->doc = doc;
10684
10685 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010686 /*
10687 * TODO: build error codes
10688 */
10689 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010690 return (1);
10691 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010692}
10693
10694#endif /* LIBXML_SCHEMAS_ENABLED */