blob: cd280343a951e1e8fa52d34fd39bc7cdcc69e2c8 [file] [log] [blame]
Daniel Veillard6eadf632003-01-23 18:29:16 +00001/*
2 * relaxng.c : implementation of the Relax-NG handling and validity checking
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <veillard@redhat.com>
7 */
8
Daniel Veillardd41f4f42003-01-29 21:07:52 +00009/**
10 * TODO:
Daniel Veillardf4b4f982003-02-13 11:02:08 +000011 * - add support for DTD compatibility spec
12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardac297932003-04-17 12:55:35 +000013 * - report better mem allocations pbms at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000014 */
15
Daniel Veillard6eadf632003-01-23 18:29:16 +000016#define IN_LIBXML
17#include "libxml.h"
18
19#ifdef LIBXML_SCHEMAS_ENABLED
20
21#include <string.h>
22#include <stdio.h>
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25#include <libxml/parserInternals.h>
26#include <libxml/hash.h>
27#include <libxml/uri.h>
28
29#include <libxml/relaxng.h>
30
31#include <libxml/xmlschemastypes.h>
32#include <libxml/xmlautomata.h>
33#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000034#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000035
36/*
37 * The Relax-NG namespace
38 */
39static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40 "http://relaxng.org/ns/structure/1.0";
41
42#define IS_RELAXNG(node, type) \
43 ((node != NULL) && (node->ns != NULL) && \
44 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
45 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
46
47
Daniel Veillard952379b2003-03-17 15:37:12 +000048/* #define DEBUG 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000049
Daniel Veillardc482e262003-02-26 14:48:48 +000050/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000051
Daniel Veillard71531f32003-02-05 13:19:53 +000052/* #define DEBUG_CONTENT 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000053
Daniel Veillard71531f32003-02-05 13:19:53 +000054/* #define DEBUG_TYPE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000055
Daniel Veillard71531f32003-02-05 13:19:53 +000056/* #define DEBUG_VALID 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000057
Daniel Veillarde5b110b2003-02-04 14:43:39 +000058/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000059
Daniel Veillard416589a2003-02-17 17:25:42 +000060/* #define DEBUG_LIST 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000061
Daniel Veillard5add8682003-03-10 13:13:58 +000062/* #define DEBUG_INCLUDE */
Daniel Veillard4c004142003-10-07 11:33:24 +000063
Daniel Veillarda507fbf2003-03-31 16:09:37 +000064/* #define DEBUG_ERROR 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000065
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000066/* #define DEBUG_COMPILE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000067
Daniel Veillardf4e55762003-04-15 23:32:22 +000068/* #define DEBUG_PROGRESSIVE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000069
Daniel Veillard5f1946a2003-03-31 16:38:16 +000070#define MAX_ERROR 5
71
Daniel Veillard6eadf632003-01-23 18:29:16 +000072#define TODO \
73 xmlGenericError(xmlGenericErrorContext, \
74 "Unimplemented block at %s:%d\n", \
75 __FILE__, __LINE__);
76
77typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
78typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
79
80typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
81typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
82
Daniel Veillardd41f4f42003-01-29 21:07:52 +000083typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
84typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
85
Daniel Veillarda9d912d2003-02-01 17:43:10 +000086typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
87typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
88
Daniel Veillard6eadf632003-01-23 18:29:16 +000089typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +000090 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
91 XML_RELAXNG_COMBINE_CHOICE, /* choice */
92 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
Daniel Veillard6eadf632003-01-23 18:29:16 +000093} xmlRelaxNGCombine;
94
Daniel Veillard4c5cf702003-02-21 15:40:34 +000095typedef enum {
96 XML_RELAXNG_CONTENT_ERROR = -1,
97 XML_RELAXNG_CONTENT_EMPTY = 0,
98 XML_RELAXNG_CONTENT_SIMPLE,
99 XML_RELAXNG_CONTENT_COMPLEX
100} xmlRelaxNGContentType;
101
Daniel Veillard6eadf632003-01-23 18:29:16 +0000102typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
103typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
104
105struct _xmlRelaxNGGrammar {
Daniel Veillard4c004142003-10-07 11:33:24 +0000106 xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
107 xmlRelaxNGGrammarPtr children; /* the children grammar if any */
108 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
109 xmlRelaxNGDefinePtr start; /* <start> content */
110 xmlRelaxNGCombine combine; /* the default combine value */
111 xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
112 xmlHashTablePtr defs; /* define* */
113 xmlHashTablePtr refs; /* references */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114};
115
116
Daniel Veillard6eadf632003-01-23 18:29:16 +0000117typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +0000118 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
119 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000120 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard4c004142003-10-07 11:33:24 +0000121 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
122 XML_RELAXNG_TEXT, /* textual content */
123 XML_RELAXNG_ELEMENT, /* an element */
124 XML_RELAXNG_DATATYPE, /* extenal data type definition */
125 XML_RELAXNG_PARAM, /* extenal data type parameter */
126 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
127 XML_RELAXNG_LIST, /* a list of patterns */
128 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
129 XML_RELAXNG_DEF, /* a definition */
130 XML_RELAXNG_REF, /* reference to a definition */
131 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
132 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
133 XML_RELAXNG_OPTIONAL, /* optional patterns */
134 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
135 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
136 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
137 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
138 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
139 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000140} xmlRelaxNGType;
141
Daniel Veillard52b48c72003-04-13 19:53:42 +0000142#define IS_NULLABLE (1 << 0)
143#define IS_NOT_NULLABLE (1 << 1)
144#define IS_INDETERMINIST (1 << 2)
145#define IS_MIXED (1 << 3)
146#define IS_TRIABLE (1 << 4)
147#define IS_PROCESSED (1 << 5)
148#define IS_COMPILABLE (1 << 6)
149#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000150
Daniel Veillard6eadf632003-01-23 18:29:16 +0000151struct _xmlRelaxNGDefine {
Daniel Veillard4c004142003-10-07 11:33:24 +0000152 xmlRelaxNGType type; /* the type of definition */
153 xmlNodePtr node; /* the node in the source */
154 xmlChar *name; /* the element local name if present */
155 xmlChar *ns; /* the namespace local name if present */
156 xmlChar *value; /* value when available */
157 void *data; /* data lib or specific pointer */
158 xmlRelaxNGDefinePtr content; /* the expected content */
159 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
160 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
161 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
162 xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
163 xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
164 short depth; /* used for the cycle detection */
165 short dflags; /* define related flags */
166 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000167};
168
169/**
170 * _xmlRelaxNG:
171 *
172 * A RelaxNGs definition
173 */
174struct _xmlRelaxNG {
Daniel Veillard4c004142003-10-07 11:33:24 +0000175 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000176 xmlRelaxNGGrammarPtr topgrammar;
177 xmlDocPtr doc;
178
Daniel Veillard4c004142003-10-07 11:33:24 +0000179 int idref; /* requires idref checking */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000180
Daniel Veillard4c004142003-10-07 11:33:24 +0000181 xmlHashTablePtr defs; /* define */
182 xmlHashTablePtr refs; /* references */
183 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
184 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
185 int defNr; /* number of defines used */
186 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000187
Daniel Veillard6eadf632003-01-23 18:29:16 +0000188};
189
Daniel Veillard77648bb2003-02-20 15:03:22 +0000190#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
191#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
192#define XML_RELAXNG_IN_LIST (1 << 2)
193#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
194#define XML_RELAXNG_IN_START (1 << 4)
195#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
196#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
197#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000198#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
199#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200
201struct _xmlRelaxNGParserCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000202 void *userData; /* user specific data block */
203 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
204 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000205 xmlStructuredErrorFunc serror;
Daniel Veillard42f12e92003-03-07 18:32:59 +0000206 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000207
Daniel Veillard4c004142003-10-07 11:33:24 +0000208 xmlRelaxNGPtr schema; /* The schema in use */
209 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
210 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
211 int flags; /* parser flags */
212 int nbErrors; /* number of errors at parse time */
213 int nbWarnings; /* number of warnings at parse time */
214 const xmlChar *define; /* the current define scope */
215 xmlRelaxNGDefinePtr def; /* the current define */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000216
Daniel Veillard4c004142003-10-07 11:33:24 +0000217 int nbInterleaves;
218 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000219
Daniel Veillard4c004142003-10-07 11:33:24 +0000220 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
221 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
222 xmlChar *URL;
223 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000224
Daniel Veillard4c004142003-10-07 11:33:24 +0000225 int defNr; /* number of defines used */
226 int defMax; /* number of defines aloocated */
227 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard419a7682003-02-03 23:22:49 +0000228
Daniel Veillard4c004142003-10-07 11:33:24 +0000229 const char *buffer;
230 int size;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000231
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000232 /* the document stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000233 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
234 int docNr; /* Depth of the parsing stack */
235 int docMax; /* Max depth of the parsing stack */
236 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000237
238 /* the include stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000239 xmlRelaxNGIncludePtr inc; /* Current parsed include */
240 int incNr; /* Depth of the include parsing stack */
241 int incMax; /* Max depth of the parsing stack */
242 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000243
Daniel Veillard4c004142003-10-07 11:33:24 +0000244 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000245
246 /* used to compile content models */
Daniel Veillard4c004142003-10-07 11:33:24 +0000247 xmlAutomataPtr am; /* the automata */
248 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard03c2f0a2004-01-25 19:54:59 +0000249
250 int crng; /* compact syntax and other flags */
Daniel Veillard42595322004-11-08 10:52:06 +0000251 int freedoc; /* need to free the document */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000252};
253
254#define FLAGS_IGNORABLE 1
255#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000256#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000257
258/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000259 * xmlRelaxNGInterleaveGroup:
260 *
261 * A RelaxNGs partition set associated to lists of definitions
262 */
263typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
264typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
265struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000266 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
267 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
268 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000269};
270
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000271#define IS_DETERMINIST 1
272#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000273
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000274/**
275 * xmlRelaxNGPartitions:
276 *
277 * A RelaxNGs partition associated to an interleave group
278 */
279typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
280typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
281struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000282 int nbgroups; /* number of groups in the partitions */
283 xmlHashTablePtr triage; /* hash table used to direct nodes to the
284 * right group when possible */
285 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000286 xmlRelaxNGInterleaveGroupPtr *groups;
287};
288
289/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000290 * xmlRelaxNGValidState:
291 *
292 * A RelaxNGs validation state
293 */
294#define MAX_ATTR 20
295typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
296typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
297struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000298 xmlNodePtr node; /* the current node */
299 xmlNodePtr seq; /* the sequence of children left to validate */
300 int nbAttrs; /* the number of attributes */
301 int maxAttrs; /* the size of attrs */
302 int nbAttrLeft; /* the number of attributes left to validate */
303 xmlChar *value; /* the value when operating on string */
304 xmlChar *endvalue; /* the end value when operating on string */
305 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000306};
307
308/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000309 * xmlRelaxNGStates:
310 *
311 * A RelaxNGs container for validation state
312 */
313typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
314typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
315struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000316 int nbState; /* the number of states */
317 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000318 xmlRelaxNGValidStatePtr *tabState;
319};
320
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000321#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000322
Daniel Veillardfd573f12003-03-16 17:52:32 +0000323/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000324 * xmlRelaxNGValidError:
325 *
326 * A RelaxNGs validation error
327 */
328typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
329typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
330struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000331 xmlRelaxNGValidErr err; /* the error number */
332 int flags; /* flags */
333 xmlNodePtr node; /* the current node */
334 xmlNodePtr seq; /* the current child */
335 const xmlChar *arg1; /* first arg */
336 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000337};
338
339/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000340 * xmlRelaxNGValidCtxt:
341 *
342 * A RelaxNGs validation context
343 */
344
345struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000346 void *userData; /* user specific data block */
347 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
348 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000349 xmlStructuredErrorFunc serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000350 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000351
Daniel Veillard4c004142003-10-07 11:33:24 +0000352 xmlRelaxNGPtr schema; /* The schema in use */
353 xmlDocPtr doc; /* the document being validated */
354 int flags; /* validation flags */
355 int depth; /* validation depth */
356 int idref; /* requires idref checking */
357 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000358
359 /*
360 * Errors accumulated in branches may have to be stacked to be
361 * provided back when it's sure they affect validation.
362 */
363 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000364 int errNr; /* Depth of the error stack */
365 int errMax; /* Max depth of the error stack */
366 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000367
Daniel Veillard4c004142003-10-07 11:33:24 +0000368 xmlRelaxNGValidStatePtr state; /* the current validation state */
369 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000370
Daniel Veillard4c004142003-10-07 11:33:24 +0000371 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
372 int freeStatesNr;
373 int freeStatesMax;
374 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000375
376 /*
377 * This is used for "progressive" validation
378 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000379 xmlRegExecCtxtPtr elem; /* the current element regexp */
380 int elemNr; /* the number of element validated */
381 int elemMax; /* the max depth of elements */
382 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
383 int pstate; /* progressive state */
384 xmlNodePtr pnode; /* the current node */
385 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
386 int perr; /* signal error in content model
387 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000388};
389
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000390/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000391 * xmlRelaxNGInclude:
392 *
393 * Structure associated to a RelaxNGs document element
394 */
395struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000396 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
397 xmlChar *href; /* the normalized href value */
398 xmlDocPtr doc; /* the associated XML document */
399 xmlRelaxNGDefinePtr content; /* the definitions */
400 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000401};
402
403/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000404 * xmlRelaxNGDocument:
405 *
406 * Structure associated to a RelaxNGs document element
407 */
408struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000409 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000410 xmlChar *href; /* the normalized href value */
411 xmlDocPtr doc; /* the associated XML document */
412 xmlRelaxNGDefinePtr content; /* the definitions */
413 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000414};
415
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000416
Daniel Veillard6eadf632003-01-23 18:29:16 +0000417/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000418 * *
419 * Some factorized error routines *
420 * *
421 ************************************************************************/
422
423/**
424 * xmlRngPErrMemory:
425 * @ctxt: an Relax-NG parser context
426 * @extra: extra informations
427 *
428 * Handle a redefinition of attribute error
429 */
430static void
431xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
432{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000433 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000434 xmlGenericErrorFunc channel = NULL;
435 void *data = NULL;
436
437 if (ctxt != NULL) {
438 channel = ctxt->error;
439 data = ctxt->userData;
440 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000441 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000442 }
443 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000444 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000445 NULL, NULL, XML_FROM_RELAXNGP,
446 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
447 NULL, NULL, 0, 0,
448 "Memory allocation failed : %s\n", extra);
449 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000450 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000451 NULL, NULL, XML_FROM_RELAXNGP,
452 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
453 NULL, NULL, 0, 0, "Memory allocation failed\n");
454}
455
456/**
457 * xmlRngVErrMemory:
458 * @ctxt: a Relax-NG validation context
459 * @extra: extra informations
460 *
461 * Handle a redefinition of attribute error
462 */
463static void
464xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
465{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000466 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000467 xmlGenericErrorFunc channel = NULL;
468 void *data = NULL;
469
470 if (ctxt != NULL) {
471 channel = ctxt->error;
472 data = ctxt->userData;
473 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000474 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000475 }
476 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000477 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000478 NULL, NULL, XML_FROM_RELAXNGV,
479 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
480 NULL, NULL, 0, 0,
481 "Memory allocation failed : %s\n", extra);
482 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000483 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000484 NULL, NULL, XML_FROM_RELAXNGV,
485 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
486 NULL, NULL, 0, 0, "Memory allocation failed\n");
487}
488
489/**
490 * xmlRngPErr:
491 * @ctxt: a Relax-NG parser context
492 * @node: the node raising the error
493 * @error: the error code
494 * @msg: message
495 * @str1: extra info
496 * @str2: extra info
497 *
498 * Handle a Relax NG Parsing error
499 */
500static void
501xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
502 const char *msg, const xmlChar * str1, const xmlChar * str2)
503{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000504 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000505 xmlGenericErrorFunc channel = NULL;
506 void *data = NULL;
507
508 if (ctxt != NULL) {
509 channel = ctxt->error;
510 data = ctxt->userData;
511 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000512 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000513 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000514 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000515 NULL, node, XML_FROM_RELAXNGP,
516 error, XML_ERR_ERROR, NULL, 0,
517 (const char *) str1, (const char *) str2, NULL, 0, 0,
518 msg, str1, str2);
519}
520
521/**
522 * xmlRngVErr:
523 * @ctxt: a Relax-NG validation context
524 * @node: the node raising the error
525 * @error: the error code
526 * @msg: message
527 * @str1: extra info
528 * @str2: extra info
529 *
530 * Handle a Relax NG Validation error
531 */
532static void
533xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
534 const char *msg, const xmlChar * str1, const xmlChar * str2)
535{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000536 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000537 xmlGenericErrorFunc channel = NULL;
538 void *data = NULL;
539
540 if (ctxt != NULL) {
541 channel = ctxt->error;
542 data = ctxt->userData;
543 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000544 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000545 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000546 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000547 NULL, node, XML_FROM_RELAXNGV,
548 error, XML_ERR_ERROR, NULL, 0,
549 (const char *) str1, (const char *) str2, NULL, 0, 0,
550 msg, str1, str2);
551}
552
553/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000554 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000555 * Preliminary type checking interfaces *
556 * *
557 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000558
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000559/**
560 * xmlRelaxNGTypeHave:
561 * @data: data needed for the library
562 * @type: the type name
563 * @value: the value to check
564 *
565 * Function provided by a type library to check if a type is exported
566 *
567 * Returns 1 if yes, 0 if no and -1 in case of error.
568 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000569typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000570
571/**
572 * xmlRelaxNGTypeCheck:
573 * @data: data needed for the library
574 * @type: the type name
575 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000576 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000577 *
578 * Function provided by a type library to check if a value match a type
579 *
580 * Returns 1 if yes, 0 if no and -1 in case of error.
581 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000582typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
583 const xmlChar * value, void **result,
584 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000585
586/**
587 * xmlRelaxNGFacetCheck:
588 * @data: data needed for the library
589 * @type: the type name
590 * @facet: the facet name
591 * @val: the facet value
592 * @strval: the string value
593 * @value: the value to check
594 *
595 * Function provided by a type library to check a value facet
596 *
597 * Returns 1 if yes, 0 if no and -1 in case of error.
598 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000599typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
600 const xmlChar * facet,
601 const xmlChar * val,
602 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000603
604/**
605 * xmlRelaxNGTypeFree:
606 * @data: data needed for the library
607 * @result: the value to free
608 *
609 * Function provided by a type library to free a returned result
610 */
611typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000612
613/**
614 * xmlRelaxNGTypeCompare:
615 * @data: data needed for the library
616 * @type: the type name
617 * @value1: the first value
618 * @value2: the second value
619 *
620 * Function provided by a type library to compare two values accordingly
621 * to a type.
622 *
623 * Returns 1 if yes, 0 if no and -1 in case of error.
624 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000625typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
626 const xmlChar * value1,
627 xmlNodePtr ctxt1,
628 void *comp1,
629 const xmlChar * value2,
630 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000631typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
632typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
633struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000634 const xmlChar *namespace; /* the datatypeLibrary value */
635 void *data; /* data needed for the library */
636 xmlRelaxNGTypeHave have; /* the export function */
637 xmlRelaxNGTypeCheck check; /* the checking function */
638 xmlRelaxNGTypeCompare comp; /* the compare function */
639 xmlRelaxNGFacetCheck facet; /* the facet check function */
640 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000641};
642
643/************************************************************************
644 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000645 * Allocation functions *
646 * *
647 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000648static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
649static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000650static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000651static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000652static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
653 ATTRIBUTE_UNUSED,
654 xmlRelaxNGValidStatePtr state1,
655 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000656static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000657 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000658
659/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000660 * xmlRelaxNGFreeDocument:
661 * @docu: a document structure
662 *
663 * Deallocate a RelaxNG document structure.
664 */
665static void
666xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
667{
668 if (docu == NULL)
669 return;
670
671 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000672 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000673 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000674 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000675 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000676 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000677 xmlFree(docu);
678}
679
680/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000681 * xmlRelaxNGFreeDocumentList:
682 * @docu: a list of document structure
683 *
684 * Deallocate a RelaxNG document structures.
685 */
686static void
687xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
688{
689 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000690
Daniel Veillardc482e262003-02-26 14:48:48 +0000691 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000692 next = docu->next;
693 xmlRelaxNGFreeDocument(docu);
694 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000695 }
696}
697
698/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000699 * xmlRelaxNGFreeInclude:
700 * @incl: a include structure
701 *
702 * Deallocate a RelaxNG include structure.
703 */
704static void
705xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
706{
707 if (incl == NULL)
708 return;
709
710 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000711 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000712 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000713 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000714 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000715 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000716 xmlFree(incl);
717}
718
719/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000720 * xmlRelaxNGFreeIncludeList:
721 * @incl: a include structure list
722 *
723 * Deallocate a RelaxNG include structure.
724 */
725static void
726xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
727{
728 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000729
Daniel Veillardc482e262003-02-26 14:48:48 +0000730 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000731 next = incl->next;
732 xmlRelaxNGFreeInclude(incl);
733 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000734 }
735}
736
737/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000738 * xmlRelaxNGNewRelaxNG:
739 * @ctxt: a Relax-NG validation context (optional)
740 *
741 * Allocate a new RelaxNG structure.
742 *
743 * Returns the newly allocated structure or NULL in case or error
744 */
745static xmlRelaxNGPtr
746xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
747{
748 xmlRelaxNGPtr ret;
749
750 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
751 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000752 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000753 return (NULL);
754 }
755 memset(ret, 0, sizeof(xmlRelaxNG));
756
757 return (ret);
758}
759
760/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000761 * xmlRelaxNGFreeInnerSchema:
762 * @schema: a schema structure
763 *
764 * Deallocate a RelaxNG schema structure.
765 */
766static void
767xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
768{
769 if (schema == NULL)
770 return;
771
772 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000773 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000774 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000775 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000776
Daniel Veillard4c004142003-10-07 11:33:24 +0000777 for (i = 0; i < schema->defNr; i++)
778 xmlRelaxNGFreeDefine(schema->defTab[i]);
779 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000780 }
781
782 xmlFree(schema);
783}
784
785/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000786 * xmlRelaxNGFree:
787 * @schema: a schema structure
788 *
789 * Deallocate a RelaxNG structure.
790 */
791void
792xmlRelaxNGFree(xmlRelaxNGPtr schema)
793{
794 if (schema == NULL)
795 return;
796
Daniel Veillard6eadf632003-01-23 18:29:16 +0000797 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000798 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000799 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000800 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000801 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000802 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000803 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000804 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000805 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000806 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000807
Daniel Veillard4c004142003-10-07 11:33:24 +0000808 for (i = 0; i < schema->defNr; i++)
809 xmlRelaxNGFreeDefine(schema->defTab[i]);
810 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000811 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000812
813 xmlFree(schema);
814}
815
816/**
817 * xmlRelaxNGNewGrammar:
818 * @ctxt: a Relax-NG validation context (optional)
819 *
820 * Allocate a new RelaxNG grammar.
821 *
822 * Returns the newly allocated structure or NULL in case or error
823 */
824static xmlRelaxNGGrammarPtr
825xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
826{
827 xmlRelaxNGGrammarPtr ret;
828
829 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
830 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000831 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000832 return (NULL);
833 }
834 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
835
836 return (ret);
837}
838
839/**
840 * xmlRelaxNGFreeGrammar:
841 * @grammar: a grammar structure
842 *
843 * Deallocate a RelaxNG grammar structure.
844 */
845static void
846xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
847{
848 if (grammar == NULL)
849 return;
850
Daniel Veillardc482e262003-02-26 14:48:48 +0000851 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000852 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000853 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000854 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000855 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000856 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000857 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000858 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000859 }
860 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000861 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000862 }
863
864 xmlFree(grammar);
865}
866
867/**
868 * xmlRelaxNGNewDefine:
869 * @ctxt: a Relax-NG validation context
870 * @node: the node in the input document.
871 *
872 * Allocate a new RelaxNG define.
873 *
874 * Returns the newly allocated structure or NULL in case or error
875 */
876static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000877xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000878{
879 xmlRelaxNGDefinePtr ret;
880
Daniel Veillard419a7682003-02-03 23:22:49 +0000881 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000882 ctxt->defMax = 16;
883 ctxt->defNr = 0;
884 ctxt->defTab = (xmlRelaxNGDefinePtr *)
885 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
886 if (ctxt->defTab == NULL) {
887 xmlRngPErrMemory(ctxt, "allocating define\n");
888 return (NULL);
889 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000890 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000891 xmlRelaxNGDefinePtr *tmp;
892
893 ctxt->defMax *= 2;
894 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
895 ctxt->defMax *
896 sizeof
897 (xmlRelaxNGDefinePtr));
898 if (tmp == NULL) {
899 xmlRngPErrMemory(ctxt, "allocating define\n");
900 return (NULL);
901 }
902 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000903 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000904 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
905 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000906 xmlRngPErrMemory(ctxt, "allocating define\n");
907 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000908 }
909 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000910 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000911 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000912 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000913 return (ret);
914}
915
916/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000917 * xmlRelaxNGFreePartition:
918 * @partitions: a partition set structure
919 *
920 * Deallocate RelaxNG partition set structures.
921 */
922static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000923xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
924{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000925 xmlRelaxNGInterleaveGroupPtr group;
926 int j;
927
928 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000929 if (partitions->groups != NULL) {
930 for (j = 0; j < partitions->nbgroups; j++) {
931 group = partitions->groups[j];
932 if (group != NULL) {
933 if (group->defs != NULL)
934 xmlFree(group->defs);
935 if (group->attrs != NULL)
936 xmlFree(group->attrs);
937 xmlFree(group);
938 }
939 }
940 xmlFree(partitions->groups);
941 }
942 if (partitions->triage != NULL) {
943 xmlHashFree(partitions->triage, NULL);
944 }
945 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000946 }
947}
Daniel Veillard4c004142003-10-07 11:33:24 +0000948
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000949/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000950 * xmlRelaxNGFreeDefine:
951 * @define: a define structure
952 *
953 * Deallocate a RelaxNG define structure.
954 */
955static void
956xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
957{
958 if (define == NULL)
959 return;
960
Daniel Veillard4c004142003-10-07 11:33:24 +0000961 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
962 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000963
Daniel Veillard4c004142003-10-07 11:33:24 +0000964 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
965 if ((lib != NULL) && (lib->freef != NULL))
966 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000967 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000968 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
969 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
970 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
971 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000972 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000973 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000974 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000975 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000976 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000977 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000978 if (define->contModel != NULL)
979 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000980 xmlFree(define);
981}
982
983/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000984 * xmlRelaxNGNewStates:
985 * @ctxt: a Relax-NG validation context
986 * @size: the default size for the container
987 *
988 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000989 *
990 * Returns the newly allocated structure or NULL in case or error
991 */
992static xmlRelaxNGStatesPtr
993xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
994{
995 xmlRelaxNGStatesPtr ret;
996
Daniel Veillard798024a2003-03-19 10:36:09 +0000997 if ((ctxt != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +0000998 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
999 ctxt->freeStatesNr--;
1000 ret = ctxt->freeStates[ctxt->freeStatesNr];
1001 ret->nbState = 0;
1002 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +00001003 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001004 if (size < 16)
1005 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001006
1007 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +00001008 (size -
1009 1) *
1010 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001011 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001012 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001013 return (NULL);
1014 }
1015 ret->nbState = 0;
1016 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001017 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1018 sizeof
1019 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001020 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001021 xmlRngVErrMemory(ctxt, "allocating states\n");
1022 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001023 return (NULL);
1024 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001025 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001026}
1027
1028/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001029 * xmlRelaxNGAddStateUniq:
1030 * @ctxt: a Relax-NG validation context
1031 * @states: the states container
1032 * @state: the validation state
1033 *
1034 * Add a RelaxNG validation state to the container without checking
1035 * for unicity.
1036 *
1037 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1038 */
1039static int
1040xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001041 xmlRelaxNGStatesPtr states,
1042 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001043{
1044 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001045 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001046 }
1047 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001048 xmlRelaxNGValidStatePtr *tmp;
1049 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001050
Daniel Veillard4c004142003-10-07 11:33:24 +00001051 size = states->maxState * 2;
1052 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1053 (size) *
1054 sizeof
1055 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001056 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001057 xmlRngVErrMemory(ctxt, "adding states\n");
1058 return (-1);
1059 }
1060 states->tabState = tmp;
1061 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001062 }
1063 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001064 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001065}
1066
1067/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001068 * xmlRelaxNGAddState:
1069 * @ctxt: a Relax-NG validation context
1070 * @states: the states container
1071 * @state: the validation state
1072 *
1073 * Add a RelaxNG validation state to the container
1074 *
1075 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1076 */
1077static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001078xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1079 xmlRelaxNGStatesPtr states,
1080 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001081{
1082 int i;
1083
1084 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001085 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001086 }
1087 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001088 xmlRelaxNGValidStatePtr *tmp;
1089 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001090
Daniel Veillard4c004142003-10-07 11:33:24 +00001091 size = states->maxState * 2;
1092 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1093 (size) *
1094 sizeof
1095 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001096 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001097 xmlRngVErrMemory(ctxt, "adding states\n");
1098 return (-1);
1099 }
1100 states->tabState = tmp;
1101 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001102 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001103 for (i = 0; i < states->nbState; i++) {
1104 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1105 xmlRelaxNGFreeValidState(ctxt, state);
1106 return (0);
1107 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001108 }
1109 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001110 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001111}
1112
1113/**
1114 * xmlRelaxNGFreeStates:
1115 * @ctxt: a Relax-NG validation context
1116 * @states: teh container
1117 *
1118 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001119 */
1120static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001121xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001122 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001123{
Daniel Veillard798024a2003-03-19 10:36:09 +00001124 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001125 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001126 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001127 ctxt->freeStatesMax = 40;
1128 ctxt->freeStatesNr = 0;
1129 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1130 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1131 if (ctxt->freeStates == NULL) {
1132 xmlRngVErrMemory(ctxt, "storing states\n");
1133 }
1134 } else if ((ctxt != NULL)
1135 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1136 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001137
Daniel Veillard4c004142003-10-07 11:33:24 +00001138 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1139 2 * ctxt->freeStatesMax *
1140 sizeof
1141 (xmlRelaxNGStatesPtr));
1142 if (tmp == NULL) {
1143 xmlRngVErrMemory(ctxt, "storing states\n");
1144 xmlFree(states->tabState);
1145 xmlFree(states);
1146 return;
1147 }
1148 ctxt->freeStates = tmp;
1149 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001150 }
1151 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001152 xmlFree(states->tabState);
1153 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001154 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001155 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001156 }
1157}
1158
1159/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001160 * xmlRelaxNGNewValidState:
1161 * @ctxt: a Relax-NG validation context
1162 * @node: the current node or NULL for the document
1163 *
1164 * Allocate a new RelaxNG validation state
1165 *
1166 * Returns the newly allocated structure or NULL in case or error
1167 */
1168static xmlRelaxNGValidStatePtr
1169xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1170{
1171 xmlRelaxNGValidStatePtr ret;
1172 xmlAttrPtr attr;
1173 xmlAttrPtr attrs[MAX_ATTR];
1174 int nbAttrs = 0;
1175 xmlNodePtr root = NULL;
1176
1177 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001178 root = xmlDocGetRootElement(ctxt->doc);
1179 if (root == NULL)
1180 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001181 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001182 attr = node->properties;
1183 while (attr != NULL) {
1184 if (nbAttrs < MAX_ATTR)
1185 attrs[nbAttrs++] = attr;
1186 else
1187 nbAttrs++;
1188 attr = attr->next;
1189 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001190 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001191 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1192 ctxt->freeState->nbState--;
1193 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001194 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001195 ret =
1196 (xmlRelaxNGValidStatePtr)
1197 xmlMalloc(sizeof(xmlRelaxNGValidState));
1198 if (ret == NULL) {
1199 xmlRngVErrMemory(ctxt, "allocating states\n");
1200 return (NULL);
1201 }
1202 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001203 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001204 ret->value = NULL;
1205 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001206 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001207 ret->node = (xmlNodePtr) ctxt->doc;
1208 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001209 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001210 ret->node = node;
1211 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001212 }
1213 ret->nbAttrs = 0;
1214 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001215 if (ret->attrs == NULL) {
1216 if (nbAttrs < 4)
1217 ret->maxAttrs = 4;
1218 else
1219 ret->maxAttrs = nbAttrs;
1220 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1221 sizeof(xmlAttrPtr));
1222 if (ret->attrs == NULL) {
1223 xmlRngVErrMemory(ctxt, "allocating states\n");
1224 return (ret);
1225 }
1226 } else if (ret->maxAttrs < nbAttrs) {
1227 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001228
Daniel Veillard4c004142003-10-07 11:33:24 +00001229 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1230 sizeof(xmlAttrPtr));
1231 if (tmp == NULL) {
1232 xmlRngVErrMemory(ctxt, "allocating states\n");
1233 return (ret);
1234 }
1235 ret->attrs = tmp;
1236 ret->maxAttrs = nbAttrs;
1237 }
1238 ret->nbAttrs = nbAttrs;
1239 if (nbAttrs < MAX_ATTR) {
1240 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1241 } else {
1242 attr = node->properties;
1243 nbAttrs = 0;
1244 while (attr != NULL) {
1245 ret->attrs[nbAttrs++] = attr;
1246 attr = attr->next;
1247 }
1248 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001249 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001250 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001251 return (ret);
1252}
1253
1254/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001255 * xmlRelaxNGCopyValidState:
1256 * @ctxt: a Relax-NG validation context
1257 * @state: a validation state
1258 *
1259 * Copy the validation state
1260 *
1261 * Returns the newly allocated structure or NULL in case or error
1262 */
1263static xmlRelaxNGValidStatePtr
1264xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001265 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001266{
1267 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001268 unsigned int maxAttrs;
1269 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001270
1271 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001272 return (NULL);
1273 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1274 ctxt->freeState->nbState--;
1275 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001276 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001277 ret =
1278 (xmlRelaxNGValidStatePtr)
1279 xmlMalloc(sizeof(xmlRelaxNGValidState));
1280 if (ret == NULL) {
1281 xmlRngVErrMemory(ctxt, "allocating states\n");
1282 return (NULL);
1283 }
1284 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001285 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001286 attrs = ret->attrs;
1287 maxAttrs = ret->maxAttrs;
1288 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1289 ret->attrs = attrs;
1290 ret->maxAttrs = maxAttrs;
1291 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001292 if (ret->attrs == NULL) {
1293 ret->maxAttrs = state->maxAttrs;
1294 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1295 sizeof(xmlAttrPtr));
1296 if (ret->attrs == NULL) {
1297 xmlRngVErrMemory(ctxt, "allocating states\n");
1298 ret->nbAttrs = 0;
1299 return (ret);
1300 }
1301 } else if (ret->maxAttrs < state->nbAttrs) {
1302 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001303
Daniel Veillard4c004142003-10-07 11:33:24 +00001304 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1305 sizeof(xmlAttrPtr));
1306 if (tmp == NULL) {
1307 xmlRngVErrMemory(ctxt, "allocating states\n");
1308 ret->nbAttrs = 0;
1309 return (ret);
1310 }
1311 ret->maxAttrs = state->maxAttrs;
1312 ret->attrs = tmp;
1313 }
1314 memcpy(ret->attrs, state->attrs,
1315 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001316 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001317 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001318}
1319
1320/**
1321 * xmlRelaxNGEqualValidState:
1322 * @ctxt: a Relax-NG validation context
1323 * @state1: a validation state
1324 * @state2: a validation state
1325 *
1326 * Compare the validation states for equality
1327 *
1328 * Returns 1 if equald, 0 otherwise
1329 */
1330static int
1331xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001332 xmlRelaxNGValidStatePtr state1,
1333 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001334{
1335 int i;
1336
1337 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001338 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001339 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001340 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001341 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001342 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001343 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001344 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001345 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001346 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001347 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001348 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001349 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001350 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001351 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001352 (!xmlStrEqual(state1->value, state2->value)))
1353 return (0);
1354 for (i = 0; i < state1->nbAttrs; i++) {
1355 if (state1->attrs[i] != state2->attrs[i])
1356 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001357 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001358 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001359}
1360
1361/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001362 * xmlRelaxNGFreeValidState:
1363 * @state: a validation state structure
1364 *
1365 * Deallocate a RelaxNG validation state structure.
1366 */
1367static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001368xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001369 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001370{
1371 if (state == NULL)
1372 return;
1373
Daniel Veillard798024a2003-03-19 10:36:09 +00001374 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001375 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001376 }
1377 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001378 if (state->attrs != NULL)
1379 xmlFree(state->attrs);
1380 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001381 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001382 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001383 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001384}
1385
1386/************************************************************************
1387 * *
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001388 * Semi internal functions *
1389 * *
1390 ************************************************************************/
1391
1392/**
1393 * xmlRelaxParserSetFlag:
1394 * @ctxt: a RelaxNG parser context
1395 * @flags: a set of flags values
1396 *
1397 * Semi private function used to pass informations to a parser context
1398 * which are a combination of xmlRelaxNGParserFlag .
1399 *
1400 * Returns 0 if success and -1 in case of error
1401 */
1402int
1403xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1404{
1405 if (ctxt == NULL) return(-1);
1406 if (flags & XML_RELAXNGP_FREE_DOC) {
1407 ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1408 flags -= XML_RELAXNGP_FREE_DOC;
1409 }
1410 if (flags & XML_RELAXNGP_CRNG) {
1411 ctxt->crng |= XML_RELAXNGP_CRNG;
1412 flags -= XML_RELAXNGP_CRNG;
1413 }
1414 if (flags != 0) return(-1);
1415 return(0);
1416}
1417
1418/************************************************************************
1419 * *
1420 * Document functions *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001421 * *
1422 ************************************************************************/
1423static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001424 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001425
1426/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 * xmlRelaxNGIncludePush:
1428 * @ctxt: the parser context
1429 * @value: the element doc
1430 *
1431 * Pushes a new include on top of the include stack
1432 *
1433 * Returns 0 in case of error, the index in the stack otherwise
1434 */
1435static int
1436xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001437 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001438{
1439 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001440 ctxt->incMax = 4;
1441 ctxt->incNr = 0;
1442 ctxt->incTab =
1443 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1444 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001445 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001446 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001447 return (0);
1448 }
1449 }
1450 if (ctxt->incNr >= ctxt->incMax) {
1451 ctxt->incMax *= 2;
1452 ctxt->incTab =
1453 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001454 ctxt->incMax *
1455 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001456 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001457 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001458 return (0);
1459 }
1460 }
1461 ctxt->incTab[ctxt->incNr] = value;
1462 ctxt->inc = value;
1463 return (ctxt->incNr++);
1464}
1465
1466/**
1467 * xmlRelaxNGIncludePop:
1468 * @ctxt: the parser context
1469 *
1470 * Pops the top include from the include stack
1471 *
1472 * Returns the include just removed
1473 */
1474static xmlRelaxNGIncludePtr
1475xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1476{
1477 xmlRelaxNGIncludePtr ret;
1478
1479 if (ctxt->incNr <= 0)
1480 return (0);
1481 ctxt->incNr--;
1482 if (ctxt->incNr > 0)
1483 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1484 else
1485 ctxt->inc = NULL;
1486 ret = ctxt->incTab[ctxt->incNr];
1487 ctxt->incTab[ctxt->incNr] = 0;
1488 return (ret);
1489}
1490
1491/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001492 * xmlRelaxNGRemoveRedefine:
1493 * @ctxt: the parser context
1494 * @URL: the normalized URL
1495 * @target: the included target
1496 * @name: the define name to eliminate
1497 *
1498 * Applies the elimination algorithm of 4.7
1499 *
1500 * Returns 0 in case of error, 1 in case of success.
1501 */
1502static int
1503xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001504 const xmlChar * URL ATTRIBUTE_UNUSED,
1505 xmlNodePtr target, const xmlChar * name)
1506{
Daniel Veillard5add8682003-03-10 13:13:58 +00001507 int found = 0;
1508 xmlNodePtr tmp, tmp2;
1509 xmlChar *name2;
1510
1511#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001512 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001513 xmlGenericError(xmlGenericErrorContext,
1514 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001515 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001516 xmlGenericError(xmlGenericErrorContext,
1517 "Elimination of <include> define %s from %s\n",
1518 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001519#endif
1520 tmp = target;
1521 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001522 tmp2 = tmp->next;
1523 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1524 found = 1;
1525 xmlUnlinkNode(tmp);
1526 xmlFreeNode(tmp);
1527 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1528 name2 = xmlGetProp(tmp, BAD_CAST "name");
1529 xmlRelaxNGNormExtSpace(name2);
1530 if (name2 != NULL) {
1531 if (xmlStrEqual(name, name2)) {
1532 found = 1;
1533 xmlUnlinkNode(tmp);
1534 xmlFreeNode(tmp);
1535 }
1536 xmlFree(name2);
1537 }
1538 } else if (IS_RELAXNG(tmp, "include")) {
1539 xmlChar *href = NULL;
Daniel Veillard807daf82004-02-22 22:13:27 +00001540 xmlRelaxNGDocumentPtr inc = tmp->psvi;
Daniel Veillard5add8682003-03-10 13:13:58 +00001541
Daniel Veillard4c004142003-10-07 11:33:24 +00001542 if ((inc != NULL) && (inc->doc != NULL) &&
1543 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001544
Daniel Veillard4c004142003-10-07 11:33:24 +00001545 if (xmlStrEqual
1546 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001547#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001548 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001549#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001550 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1551 inc->doc->children->
1552 children, name) == 1) {
1553 found = 1;
1554 }
1555 if (href != NULL)
1556 xmlFree(href);
1557 }
1558 }
1559 }
1560 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001561 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001562 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001563}
1564
1565/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001566 * xmlRelaxNGLoadInclude:
1567 * @ctxt: the parser context
1568 * @URL: the normalized URL
1569 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001570 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001571 *
1572 * First lookup if the document is already loaded into the parser context,
1573 * check against recursion. If not found the resource is loaded and
1574 * the content is preprocessed before being returned back to the caller.
1575 *
1576 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1577 */
1578static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001579xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1580 xmlNodePtr node, const xmlChar * ns)
1581{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001582 xmlRelaxNGIncludePtr ret = NULL;
1583 xmlDocPtr doc;
1584 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001585 xmlNodePtr root, cur;
1586
1587#ifdef DEBUG_INCLUDE
1588 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001589 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001590#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001591
1592 /*
1593 * check against recursion in the stack
1594 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001595 for (i = 0; i < ctxt->incNr; i++) {
1596 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1597 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1598 "Detected an Include recursion for %s\n", URL,
1599 NULL);
1600 return (NULL);
1601 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001602 }
1603
1604 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001605 * load the document
1606 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001607 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001608 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001609 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1610 "xmlRelaxNG: could not load %s\n", URL, NULL);
1611 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001612 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001613#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001614 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001615#endif
1616
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001617 /*
1618 * Allocate the document structures and register it first.
1619 */
1620 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1621 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001622 xmlRngPErrMemory(ctxt, "allocating include\n");
1623 xmlFreeDoc(doc);
1624 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001625 }
1626 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1627 ret->doc = doc;
1628 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001629 ret->next = ctxt->includes;
1630 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001631
1632 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001633 * transmit the ns if needed
1634 */
1635 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001636 root = xmlDocGetRootElement(doc);
1637 if (root != NULL) {
1638 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1639 xmlSetProp(root, BAD_CAST "ns", ns);
1640 }
1641 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001642 }
1643
1644 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001645 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001646 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001647 xmlRelaxNGIncludePush(ctxt, ret);
1648
1649 /*
1650 * Some preprocessing of the document content, this include recursing
1651 * in the include stack.
1652 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001653#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001654 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001655#endif
1656
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001657 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1658 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001659 ctxt->inc = NULL;
1660 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001661 }
1662
1663 /*
1664 * Pop up the include from the stack
1665 */
1666 xmlRelaxNGIncludePop(ctxt);
1667
Daniel Veillard5add8682003-03-10 13:13:58 +00001668#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001669 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001670#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001671 /*
1672 * Check that the top element is a grammar
1673 */
1674 root = xmlDocGetRootElement(doc);
1675 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001676 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1677 "xmlRelaxNG: included document is empty %s\n", URL,
1678 NULL);
1679 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001680 }
1681 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001682 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1683 "xmlRelaxNG: included document %s root is not a grammar\n",
1684 URL, NULL);
1685 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001686 }
1687
1688 /*
1689 * Elimination of redefined rules in the include.
1690 */
1691 cur = node->children;
1692 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001693 if (IS_RELAXNG(cur, "start")) {
1694 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001695
Daniel Veillard4c004142003-10-07 11:33:24 +00001696 found =
1697 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1698 if (!found) {
1699 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1700 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1701 URL, NULL);
1702 }
1703 } else if (IS_RELAXNG(cur, "define")) {
1704 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001705
Daniel Veillard4c004142003-10-07 11:33:24 +00001706 name = xmlGetProp(cur, BAD_CAST "name");
1707 if (name == NULL) {
1708 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1709 "xmlRelaxNG: include %s has define without name\n",
1710 URL, NULL);
1711 } else {
1712 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001713
Daniel Veillard4c004142003-10-07 11:33:24 +00001714 xmlRelaxNGNormExtSpace(name);
1715 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1716 root->children, name);
1717 if (!found) {
1718 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1719 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1720 URL, name);
1721 }
1722 xmlFree(name);
1723 }
1724 }
1725 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001726 }
1727
1728
Daniel Veillard4c004142003-10-07 11:33:24 +00001729 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001730}
1731
1732/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001733 * xmlRelaxNGValidErrorPush:
1734 * @ctxt: the validation context
1735 * @err: the error code
1736 * @arg1: the first string argument
1737 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001738 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001739 *
1740 * Pushes a new error on top of the error stack
1741 *
1742 * Returns 0 in case of error, the index in the stack otherwise
1743 */
1744static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001745xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1746 xmlRelaxNGValidErr err, const xmlChar * arg1,
1747 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001748{
1749 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001750
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001751#ifdef DEBUG_ERROR
1752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001753 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001754#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001755 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001756 ctxt->errMax = 8;
1757 ctxt->errNr = 0;
1758 ctxt->errTab =
1759 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1760 sizeof
1761 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001762 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001763 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001764 return (0);
1765 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001766 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001767 }
1768 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001769 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001770 ctxt->errTab =
1771 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001772 ctxt->errMax *
1773 sizeof
1774 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001775 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001776 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001777 return (0);
1778 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001779 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001780 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001781 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001782 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1783 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001784 cur = &ctxt->errTab[ctxt->errNr];
1785 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001786 if (dup) {
1787 cur->arg1 = xmlStrdup(arg1);
1788 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001789 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001790 } else {
1791 cur->arg1 = arg1;
1792 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001793 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001794 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001795 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001796 cur->node = ctxt->state->node;
1797 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001798 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001799 cur->node = NULL;
1800 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001801 }
1802 ctxt->err = cur;
1803 return (ctxt->errNr++);
1804}
1805
1806/**
1807 * xmlRelaxNGValidErrorPop:
1808 * @ctxt: the validation context
1809 *
1810 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001811 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001812static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001813xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1814{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001815 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001816
Daniel Veillard580ced82003-03-21 21:22:48 +00001817 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001818 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001819 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001820 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001821 ctxt->errNr--;
1822 if (ctxt->errNr > 0)
1823 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1824 else
1825 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001826 cur = &ctxt->errTab[ctxt->errNr];
1827 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001828 if (cur->arg1 != NULL)
1829 xmlFree((xmlChar *) cur->arg1);
1830 cur->arg1 = NULL;
1831 if (cur->arg2 != NULL)
1832 xmlFree((xmlChar *) cur->arg2);
1833 cur->arg2 = NULL;
1834 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001835 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001836}
1837
Daniel Veillard42f12e92003-03-07 18:32:59 +00001838/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001839 * xmlRelaxNGDocumentPush:
1840 * @ctxt: the parser context
1841 * @value: the element doc
1842 *
1843 * Pushes a new doc on top of the doc stack
1844 *
1845 * Returns 0 in case of error, the index in the stack otherwise
1846 */
1847static int
1848xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001849 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001850{
1851 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001852 ctxt->docMax = 4;
1853 ctxt->docNr = 0;
1854 ctxt->docTab =
1855 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1856 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001857 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001858 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001859 return (0);
1860 }
1861 }
1862 if (ctxt->docNr >= ctxt->docMax) {
1863 ctxt->docMax *= 2;
1864 ctxt->docTab =
1865 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001866 ctxt->docMax *
1867 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001868 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001869 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001870 return (0);
1871 }
1872 }
1873 ctxt->docTab[ctxt->docNr] = value;
1874 ctxt->doc = value;
1875 return (ctxt->docNr++);
1876}
1877
1878/**
1879 * xmlRelaxNGDocumentPop:
1880 * @ctxt: the parser context
1881 *
1882 * Pops the top doc from the doc stack
1883 *
1884 * Returns the doc just removed
1885 */
1886static xmlRelaxNGDocumentPtr
1887xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1888{
1889 xmlRelaxNGDocumentPtr ret;
1890
1891 if (ctxt->docNr <= 0)
1892 return (0);
1893 ctxt->docNr--;
1894 if (ctxt->docNr > 0)
1895 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1896 else
1897 ctxt->doc = NULL;
1898 ret = ctxt->docTab[ctxt->docNr];
1899 ctxt->docTab[ctxt->docNr] = 0;
1900 return (ret);
1901}
1902
1903/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001904 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001905 * @ctxt: the parser context
1906 * @URL: the normalized URL
1907 * @ns: the inherited ns if any
1908 *
1909 * First lookup if the document is already loaded into the parser context,
1910 * check against recursion. If not found the resource is loaded and
1911 * the content is preprocessed before being returned back to the caller.
1912 *
1913 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1914 */
1915static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001916xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1917 const xmlChar * URL, const xmlChar * ns)
1918{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001919 xmlRelaxNGDocumentPtr ret = NULL;
1920 xmlDocPtr doc;
1921 xmlNodePtr root;
1922 int i;
1923
1924 /*
1925 * check against recursion in the stack
1926 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001927 for (i = 0; i < ctxt->docNr; i++) {
1928 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1929 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1930 "Detected an externalRef recursion for %s\n", URL,
1931 NULL);
1932 return (NULL);
1933 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001934 }
1935
1936 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001937 * load the document
1938 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001939 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001940 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001941 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1942 "xmlRelaxNG: could not load %s\n", URL, NULL);
1943 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001944 }
1945
1946 /*
1947 * Allocate the document structures and register it first.
1948 */
1949 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1950 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001951 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1952 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1953 xmlFreeDoc(doc);
1954 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001955 }
1956 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1957 ret->doc = doc;
1958 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001959 ret->next = ctxt->documents;
1960 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001961
1962 /*
1963 * transmit the ns if needed
1964 */
1965 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001966 root = xmlDocGetRootElement(doc);
1967 if (root != NULL) {
1968 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1969 xmlSetProp(root, BAD_CAST "ns", ns);
1970 }
1971 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001972 }
1973
1974 /*
1975 * push it on the stack and register it in the hash table
1976 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001977 xmlRelaxNGDocumentPush(ctxt, ret);
1978
1979 /*
1980 * Some preprocessing of the document content
1981 */
1982 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1983 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001984 ctxt->doc = NULL;
1985 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001986 }
1987
1988 xmlRelaxNGDocumentPop(ctxt);
1989
Daniel Veillard4c004142003-10-07 11:33:24 +00001990 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001991}
1992
1993/************************************************************************
1994 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001995 * Error functions *
1996 * *
1997 ************************************************************************/
1998
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001999#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2000#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2001#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2002#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2003#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002004
Daniel Veillard231d7912003-02-09 14:22:17 +00002005static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00002006xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2007{
Daniel Veillard231d7912003-02-09 14:22:17 +00002008 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002009 return ("none");
2010 switch (def->type) {
2011 case XML_RELAXNG_EMPTY:
2012 return ("empty");
2013 case XML_RELAXNG_NOT_ALLOWED:
2014 return ("notAllowed");
2015 case XML_RELAXNG_EXCEPT:
2016 return ("except");
2017 case XML_RELAXNG_TEXT:
2018 return ("text");
2019 case XML_RELAXNG_ELEMENT:
2020 return ("element");
2021 case XML_RELAXNG_DATATYPE:
2022 return ("datatype");
2023 case XML_RELAXNG_VALUE:
2024 return ("value");
2025 case XML_RELAXNG_LIST:
2026 return ("list");
2027 case XML_RELAXNG_ATTRIBUTE:
2028 return ("attribute");
2029 case XML_RELAXNG_DEF:
2030 return ("def");
2031 case XML_RELAXNG_REF:
2032 return ("ref");
2033 case XML_RELAXNG_EXTERNALREF:
2034 return ("externalRef");
2035 case XML_RELAXNG_PARENTREF:
2036 return ("parentRef");
2037 case XML_RELAXNG_OPTIONAL:
2038 return ("optional");
2039 case XML_RELAXNG_ZEROORMORE:
2040 return ("zeroOrMore");
2041 case XML_RELAXNG_ONEORMORE:
2042 return ("oneOrMore");
2043 case XML_RELAXNG_CHOICE:
2044 return ("choice");
2045 case XML_RELAXNG_GROUP:
2046 return ("group");
2047 case XML_RELAXNG_INTERLEAVE:
2048 return ("interleave");
2049 case XML_RELAXNG_START:
2050 return ("start");
2051 case XML_RELAXNG_NOOP:
2052 return ("noop");
2053 case XML_RELAXNG_PARAM:
2054 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002055 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002056 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002057}
Daniel Veillardd2298792003-02-14 16:54:11 +00002058
Daniel Veillard6eadf632003-01-23 18:29:16 +00002059/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002060 * xmlRelaxNGGetErrorString:
2061 * @err: the error code
2062 * @arg1: the first string argument
2063 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002064 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002065 * computes a formatted error string for the given error code and args
2066 *
2067 * Returns the error string, it must be deallocated by the caller
2068 */
2069static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002070xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2071 const xmlChar * arg2)
2072{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002073 char msg[1000];
2074
2075 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002076 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002077 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002078 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002079
2080 msg[0] = 0;
2081 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002082 case XML_RELAXNG_OK:
2083 return (NULL);
2084 case XML_RELAXNG_ERR_MEMORY:
2085 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002086 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002087 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2088 break;
2089 case XML_RELAXNG_ERR_TYPEVAL:
2090 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2091 arg2);
2092 break;
2093 case XML_RELAXNG_ERR_DUPID:
2094 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2095 break;
2096 case XML_RELAXNG_ERR_TYPECMP:
2097 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2098 break;
2099 case XML_RELAXNG_ERR_NOSTATE:
2100 return (xmlCharStrdup("Internal error: no state\n"));
2101 case XML_RELAXNG_ERR_NODEFINE:
2102 return (xmlCharStrdup("Internal error: no define\n"));
2103 case XML_RELAXNG_ERR_INTERNAL:
2104 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2105 break;
2106 case XML_RELAXNG_ERR_LISTEXTRA:
2107 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2108 break;
2109 case XML_RELAXNG_ERR_INTERNODATA:
2110 return (xmlCharStrdup
2111 ("Internal: interleave block has no data\n"));
2112 case XML_RELAXNG_ERR_INTERSEQ:
2113 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2114 case XML_RELAXNG_ERR_INTEREXTRA:
2115 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2116 break;
2117 case XML_RELAXNG_ERR_ELEMNAME:
2118 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2119 arg2);
2120 break;
2121 case XML_RELAXNG_ERR_ELEMNONS:
2122 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2123 arg1);
2124 break;
2125 case XML_RELAXNG_ERR_ELEMWRONGNS:
2126 snprintf(msg, 1000,
2127 "Element %s has wrong namespace: expecting %s\n", arg1,
2128 arg2);
2129 break;
2130 case XML_RELAXNG_ERR_ELEMWRONG:
2131 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2132 break;
2133 case XML_RELAXNG_ERR_TEXTWRONG:
2134 snprintf(msg, 1000,
2135 "Did not expect text in element %s content\n", arg1);
2136 break;
2137 case XML_RELAXNG_ERR_ELEMEXTRANS:
2138 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2139 arg1);
2140 break;
2141 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2142 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2143 break;
2144 case XML_RELAXNG_ERR_NOELEM:
2145 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2146 arg1);
2147 break;
2148 case XML_RELAXNG_ERR_NOTELEM:
2149 return (xmlCharStrdup("Expecting an element got text\n"));
2150 case XML_RELAXNG_ERR_ATTRVALID:
2151 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2152 arg1);
2153 break;
2154 case XML_RELAXNG_ERR_CONTENTVALID:
2155 snprintf(msg, 1000, "Element %s failed to validate content\n",
2156 arg1);
2157 break;
2158 case XML_RELAXNG_ERR_EXTRACONTENT:
2159 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2160 arg1, arg2);
2161 break;
2162 case XML_RELAXNG_ERR_INVALIDATTR:
2163 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2164 arg1, arg2);
2165 break;
2166 case XML_RELAXNG_ERR_LACKDATA:
2167 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2168 arg1);
2169 break;
2170 case XML_RELAXNG_ERR_DATAELEM:
2171 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2172 arg1);
2173 break;
2174 case XML_RELAXNG_ERR_VALELEM:
2175 snprintf(msg, 1000, "Value element %s has child elements\n",
2176 arg1);
2177 break;
2178 case XML_RELAXNG_ERR_LISTELEM:
2179 snprintf(msg, 1000, "List element %s has child elements\n",
2180 arg1);
2181 break;
2182 case XML_RELAXNG_ERR_DATATYPE:
2183 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2184 break;
2185 case XML_RELAXNG_ERR_VALUE:
2186 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2187 break;
2188 case XML_RELAXNG_ERR_LIST:
2189 return (xmlCharStrdup("Error validating list\n"));
2190 case XML_RELAXNG_ERR_NOGRAMMAR:
2191 return (xmlCharStrdup("No top grammar defined\n"));
2192 case XML_RELAXNG_ERR_EXTRADATA:
2193 return (xmlCharStrdup("Extra data in the document\n"));
2194 default:
2195 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002196 }
2197 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002198 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002199 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002200 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002201 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002202}
2203
2204/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002205 * xmlRelaxNGShowValidError:
2206 * @ctxt: the validation context
2207 * @err: the error number
2208 * @node: the node
2209 * @child: the node child generating the problem.
2210 * @arg1: the first argument
2211 * @arg2: the second argument
2212 *
2213 * Show a validation error.
2214 */
2215static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002216xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2217 xmlRelaxNGValidErr err, xmlNodePtr node,
2218 xmlNodePtr child, const xmlChar * arg1,
2219 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002220{
2221 xmlChar *msg;
2222
2223 if (ctxt->error == NULL)
2224 return;
2225
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002226#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002227 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002228#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002229 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2230 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002231 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002232
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002233 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002234 ctxt->errNo = err;
2235 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2236 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002237 xmlFree(msg);
2238}
2239
2240/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002241 * xmlRelaxNGPopErrors:
2242 * @ctxt: the validation context
2243 * @level: the error level in the stack
2244 *
2245 * pop and discard all errors until the given level is reached
2246 */
2247static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002248xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2249{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002250 int i;
2251 xmlRelaxNGValidErrorPtr err;
2252
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002253#ifdef DEBUG_ERROR
2254 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002255 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002256#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002257 for (i = level; i < ctxt->errNr; i++) {
2258 err = &ctxt->errTab[i];
2259 if (err->flags & ERROR_IS_DUP) {
2260 if (err->arg1 != NULL)
2261 xmlFree((xmlChar *) err->arg1);
2262 err->arg1 = NULL;
2263 if (err->arg2 != NULL)
2264 xmlFree((xmlChar *) err->arg2);
2265 err->arg2 = NULL;
2266 err->flags = 0;
2267 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002268 }
2269 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002270 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002271 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002272}
Daniel Veillard4c004142003-10-07 11:33:24 +00002273
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002274/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002275 * xmlRelaxNGDumpValidError:
2276 * @ctxt: the validation context
2277 *
2278 * Show all validation error over a given index.
2279 */
2280static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002281xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2282{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002283 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002284 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002285
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002286#ifdef DEBUG_ERROR
2287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002288 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002289#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002290 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2291 err = &ctxt->errTab[i];
2292 if (k < MAX_ERROR) {
2293 for (j = 0; j < i; j++) {
2294 dup = &ctxt->errTab[j];
2295 if ((err->err == dup->err) && (err->node == dup->node) &&
2296 (xmlStrEqual(err->arg1, dup->arg1)) &&
2297 (xmlStrEqual(err->arg2, dup->arg2))) {
2298 goto skip;
2299 }
2300 }
2301 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2302 err->arg1, err->arg2);
2303 k++;
2304 }
2305 skip:
2306 if (err->flags & ERROR_IS_DUP) {
2307 if (err->arg1 != NULL)
2308 xmlFree((xmlChar *) err->arg1);
2309 err->arg1 = NULL;
2310 if (err->arg2 != NULL)
2311 xmlFree((xmlChar *) err->arg2);
2312 err->arg2 = NULL;
2313 err->flags = 0;
2314 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002315 }
2316 ctxt->errNr = 0;
2317}
Daniel Veillard4c004142003-10-07 11:33:24 +00002318
Daniel Veillard42f12e92003-03-07 18:32:59 +00002319/**
2320 * xmlRelaxNGAddValidError:
2321 * @ctxt: the validation context
2322 * @err: the error number
2323 * @arg1: the first argument
2324 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002325 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002326 *
2327 * Register a validation error, either generating it if it's sure
2328 * or stacking it for later handling if unsure.
2329 */
2330static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002331xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2332 xmlRelaxNGValidErr err, const xmlChar * arg1,
2333 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002334{
2335 if ((ctxt == NULL) || (ctxt->error == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002336 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002337
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002338#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002339 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002340#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002341 /*
2342 * generate the error directly
2343 */
William M. Brack60929622004-03-27 17:54:18 +00002344 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2345 (ctxt->flags & FLAGS_NEGATIVE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002346 xmlNodePtr node, seq;
2347
2348 /*
2349 * Flush first any stacked error which might be the
2350 * real cause of the problem.
2351 */
2352 if (ctxt->errNr != 0)
2353 xmlRelaxNGDumpValidError(ctxt);
2354 if (ctxt->state != NULL) {
2355 node = ctxt->state->node;
2356 seq = ctxt->state->seq;
2357 } else {
2358 node = seq = NULL;
2359 }
2360 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002361 }
2362 /*
2363 * Stack the error for later processing if needed
2364 */
2365 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002366 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002367 }
2368}
2369
Daniel Veillard6eadf632003-01-23 18:29:16 +00002370
2371/************************************************************************
2372 * *
2373 * Type library hooks *
2374 * *
2375 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002376static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002377 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002378
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002379/**
2380 * xmlRelaxNGSchemaTypeHave:
2381 * @data: data needed for the library
2382 * @type: the type name
2383 *
2384 * Check if the given type is provided by
2385 * the W3C XMLSchema Datatype library.
2386 *
2387 * Returns 1 if yes, 0 if no and -1 in case of error.
2388 */
2389static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002390xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2391{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002392 xmlSchemaTypePtr typ;
2393
2394 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002395 return (-1);
2396 typ = xmlSchemaGetPredefinedType(type,
2397 BAD_CAST
2398 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002399 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002400 return (0);
2401 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002402}
2403
2404/**
2405 * xmlRelaxNGSchemaTypeCheck:
2406 * @data: data needed for the library
2407 * @type: the type name
2408 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002409 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002410 *
2411 * Check if the given type and value are validated by
2412 * the W3C XMLSchema Datatype library.
2413 *
2414 * Returns 1 if yes, 0 if no and -1 in case of error.
2415 */
2416static int
2417xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002418 const xmlChar * type,
2419 const xmlChar * value,
2420 void **result, xmlNodePtr node)
2421{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002422 xmlSchemaTypePtr typ;
2423 int ret;
2424
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002425 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002426 return (-1);
2427 typ = xmlSchemaGetPredefinedType(type,
2428 BAD_CAST
2429 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002430 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002431 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002432 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002433 (xmlSchemaValPtr *) result, node);
2434 if (ret == 2) /* special ID error code */
2435 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002436 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002437 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002438 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002439 return (0);
2440 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002441}
2442
2443/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002444 * xmlRelaxNGSchemaFacetCheck:
2445 * @data: data needed for the library
2446 * @type: the type name
2447 * @facet: the facet name
2448 * @val: the facet value
2449 * @strval: the string value
2450 * @value: the value to check
2451 *
2452 * Function provided by a type library to check a value facet
2453 *
2454 * Returns 1 if yes, 0 if no and -1 in case of error.
2455 */
2456static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002457xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2458 const xmlChar * type, const xmlChar * facetname,
2459 const xmlChar * val, const xmlChar * strval,
2460 void *value)
2461{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002462 xmlSchemaFacetPtr facet;
2463 xmlSchemaTypePtr typ;
2464 int ret;
2465
2466 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002467 return (-1);
2468 typ = xmlSchemaGetPredefinedType(type,
2469 BAD_CAST
2470 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002471 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002472 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002473
2474 facet = xmlSchemaNewFacet();
2475 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002476 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002477
Daniel Veillard4c004142003-10-07 11:33:24 +00002478 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002479 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002480 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002481 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002482 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002483 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002484 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002485 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002486 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002487 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002488 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002489 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002490 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002491 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002492 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002493 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002494 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002495 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002496 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002497 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002498 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002499 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2500 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2501 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2502 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002503 xmlSchemaFreeFacet(facet);
2504 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002505 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002506 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002507 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2508 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002509 xmlSchemaFreeFacet(facet);
2510 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002511 }
2512 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2513 xmlSchemaFreeFacet(facet);
2514 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002515 return (-1);
2516 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002517}
2518
2519/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002520 * xmlRelaxNGSchemaFreeValue:
2521 * @data: data needed for the library
2522 * @value: the value to free
2523 *
2524 * Function provided by a type library to free a Schemas value
2525 *
2526 * Returns 1 if yes, 0 if no and -1 in case of error.
2527 */
2528static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002529xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2530{
Daniel Veillard80b19092003-03-28 13:29:53 +00002531 xmlSchemaFreeValue(value);
2532}
2533
2534/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002535 * xmlRelaxNGSchemaTypeCompare:
2536 * @data: data needed for the library
2537 * @type: the type name
2538 * @value1: the first value
2539 * @value2: the second value
2540 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002541 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002542 * Datatype library.
2543 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002544 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002545 */
2546static int
2547xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002548 const xmlChar * type,
2549 const xmlChar * value1,
2550 xmlNodePtr ctxt1,
2551 void *comp1,
2552 const xmlChar * value2, xmlNodePtr ctxt2)
2553{
Daniel Veillard80b19092003-03-28 13:29:53 +00002554 int ret;
2555 xmlSchemaTypePtr typ;
2556 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2557
2558 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002559 return (-1);
2560 typ = xmlSchemaGetPredefinedType(type,
2561 BAD_CAST
2562 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002563 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002564 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002565 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002566 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2567 if (ret != 0)
2568 return (-1);
2569 if (res1 == NULL)
2570 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002571 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002572 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002573 }
2574 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002575 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002576 xmlSchemaFreeValue(res1);
2577 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002578 }
2579 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002580 xmlSchemaFreeValue(res1);
2581 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002582 }
2583 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002584 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002585 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002586 xmlSchemaFreeValue(res2);
2587 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002588 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002589 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002590 return (1);
2591 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002592}
Daniel Veillard4c004142003-10-07 11:33:24 +00002593
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002594/**
2595 * xmlRelaxNGDefaultTypeHave:
2596 * @data: data needed for the library
2597 * @type: the type name
2598 *
2599 * Check if the given type is provided by
2600 * the default datatype library.
2601 *
2602 * Returns 1 if yes, 0 if no and -1 in case of error.
2603 */
2604static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002605xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2606 const xmlChar * type)
2607{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002608 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002609 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002610 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002611 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002612 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002613 return (1);
2614 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002615}
2616
2617/**
2618 * xmlRelaxNGDefaultTypeCheck:
2619 * @data: data needed for the library
2620 * @type: the type name
2621 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002622 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002623 *
2624 * Check if the given type and value are validated by
2625 * the default datatype library.
2626 *
2627 * Returns 1 if yes, 0 if no and -1 in case of error.
2628 */
2629static int
2630xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002631 const xmlChar * type ATTRIBUTE_UNUSED,
2632 const xmlChar * value ATTRIBUTE_UNUSED,
2633 void **result ATTRIBUTE_UNUSED,
2634 xmlNodePtr node ATTRIBUTE_UNUSED)
2635{
Daniel Veillardd4310742003-02-18 21:12:46 +00002636 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002637 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002638 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002639 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002640 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002641 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002642 }
2643
Daniel Veillard4c004142003-10-07 11:33:24 +00002644 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002645}
2646
2647/**
2648 * xmlRelaxNGDefaultTypeCompare:
2649 * @data: data needed for the library
2650 * @type: the type name
2651 * @value1: the first value
2652 * @value2: the second value
2653 *
2654 * Compare two values accordingly a type from the default
2655 * datatype library.
2656 *
2657 * Returns 1 if yes, 0 if no and -1 in case of error.
2658 */
2659static int
2660xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002661 const xmlChar * type,
2662 const xmlChar * value1,
2663 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2664 void *comp1 ATTRIBUTE_UNUSED,
2665 const xmlChar * value2,
2666 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2667{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002668 int ret = -1;
2669
2670 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002671 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002672 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002673 if (!xmlStrEqual(value1, value2)) {
2674 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002675
Daniel Veillard4c004142003-10-07 11:33:24 +00002676 /*
2677 * TODO: trivial optimizations are possible by
2678 * computing at compile-time
2679 */
2680 nval = xmlRelaxNGNormalize(NULL, value1);
2681 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002682
Daniel Veillard4c004142003-10-07 11:33:24 +00002683 if ((nval == NULL) || (nvalue == NULL))
2684 ret = -1;
2685 else if (xmlStrEqual(nval, nvalue))
2686 ret = 1;
2687 else
2688 ret = 0;
2689 if (nval != NULL)
2690 xmlFree(nval);
2691 if (nvalue != NULL)
2692 xmlFree(nvalue);
2693 } else
2694 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002695 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002696 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002697}
Daniel Veillard4c004142003-10-07 11:33:24 +00002698
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002699static int xmlRelaxNGTypeInitialized = 0;
2700static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2701
2702/**
2703 * xmlRelaxNGFreeTypeLibrary:
2704 * @lib: the type library structure
2705 * @namespace: the URI bound to the library
2706 *
2707 * Free the structure associated to the type library
2708 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002709static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002710xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002711 const xmlChar * namespace ATTRIBUTE_UNUSED)
2712{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002713 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002714 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002715 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002716 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002717 xmlFree(lib);
2718}
2719
2720/**
2721 * xmlRelaxNGRegisterTypeLibrary:
2722 * @namespace: the URI bound to the library
2723 * @data: data associated to the library
2724 * @have: the provide function
2725 * @check: the checking function
2726 * @comp: the comparison function
2727 *
2728 * Register a new type library
2729 *
2730 * Returns 0 in case of success and -1 in case of error.
2731 */
2732static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002733xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2734 xmlRelaxNGTypeHave have,
2735 xmlRelaxNGTypeCheck check,
2736 xmlRelaxNGTypeCompare comp,
2737 xmlRelaxNGFacetCheck facet,
2738 xmlRelaxNGTypeFree freef)
2739{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002740 xmlRelaxNGTypeLibraryPtr lib;
2741 int ret;
2742
2743 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002744 (check == NULL) || (comp == NULL))
2745 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002746 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002747 xmlGenericError(xmlGenericErrorContext,
2748 "Relax-NG types library '%s' already registered\n",
2749 namespace);
2750 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002751 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002752 lib =
2753 (xmlRelaxNGTypeLibraryPtr)
2754 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002755 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002756 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002757 return (-1);
2758 }
2759 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2760 lib->namespace = xmlStrdup(namespace);
2761 lib->data = data;
2762 lib->have = have;
2763 lib->comp = comp;
2764 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002765 lib->facet = facet;
2766 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002767 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2768 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002769 xmlGenericError(xmlGenericErrorContext,
2770 "Relax-NG types library failed to register '%s'\n",
2771 namespace);
2772 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2773 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002774 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002775 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002776}
2777
2778/**
2779 * xmlRelaxNGInitTypes:
2780 *
2781 * Initilize the default type libraries.
2782 *
2783 * Returns 0 in case of success and -1 in case of error.
2784 */
Daniel Veillarddd6d3002004-11-03 14:20:29 +00002785int
Daniel Veillard4c004142003-10-07 11:33:24 +00002786xmlRelaxNGInitTypes(void)
2787{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002788 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002789 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002790 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2791 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002792 xmlGenericError(xmlGenericErrorContext,
2793 "Failed to allocate sh table for Relax-NG types\n");
2794 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002795 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002796 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2797 "http://www.w3.org/2001/XMLSchema-datatypes",
2798 NULL, xmlRelaxNGSchemaTypeHave,
2799 xmlRelaxNGSchemaTypeCheck,
2800 xmlRelaxNGSchemaTypeCompare,
2801 xmlRelaxNGSchemaFacetCheck,
2802 xmlRelaxNGSchemaFreeValue);
2803 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2804 xmlRelaxNGDefaultTypeHave,
2805 xmlRelaxNGDefaultTypeCheck,
2806 xmlRelaxNGDefaultTypeCompare, NULL,
2807 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002808 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002809 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002810}
2811
2812/**
2813 * xmlRelaxNGCleanupTypes:
2814 *
2815 * Cleanup the default Schemas type library associated to RelaxNG
2816 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002817void
2818xmlRelaxNGCleanupTypes(void)
2819{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002820 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002821 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002822 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002823 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002824 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002825 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002826}
2827
2828/************************************************************************
2829 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002830 * Compiling element content into regexp *
2831 * *
2832 * Sometime the element content can be compiled into a pure regexp, *
2833 * This allows a faster execution and streamability at that level *
2834 * *
2835 ************************************************************************/
2836
Daniel Veillard52b48c72003-04-13 19:53:42 +00002837static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2838 xmlRelaxNGDefinePtr def);
2839
Daniel Veillard952379b2003-03-17 15:37:12 +00002840/**
2841 * xmlRelaxNGIsCompileable:
2842 * @define: the definition to check
2843 *
2844 * Check if a definition is nullable.
2845 *
2846 * Returns 1 if yes, 0 if no and -1 in case of error
2847 */
2848static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002849xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2850{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002851 int ret = -1;
2852
Daniel Veillard952379b2003-03-17 15:37:12 +00002853 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002854 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002855 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002856 if ((def->type != XML_RELAXNG_ELEMENT) &&
2857 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002858 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002859 if ((def->type != XML_RELAXNG_ELEMENT) &&
2860 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002861 return (0);
2862 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002863 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002864 ret = xmlRelaxNGIsCompileable(def->content);
2865 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002866 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002867 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002868 ret = 1;
2869 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002870 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002871 /*
2872 * Check if the element content is compileable
2873 */
2874 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2875 ((def->dflags & IS_COMPILABLE) == 0)) {
2876 xmlRelaxNGDefinePtr list;
2877
2878 list = def->content;
2879 while (list != NULL) {
2880 ret = xmlRelaxNGIsCompileable(list);
2881 if (ret != 1)
2882 break;
2883 list = list->next;
2884 }
William M. Brack60929622004-03-27 17:54:18 +00002885 /*
2886 * Because the routine is recursive, we must guard against
2887 * discovering both COMPILABLE and NOT_COMPILABLE
2888 */
2889 if (ret == 0) {
2890 def->dflags &= ~IS_COMPILABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002891 def->dflags |= IS_NOT_COMPILABLE;
William M. Brack60929622004-03-27 17:54:18 +00002892 }
2893 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002894 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002895#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002896 if (ret == 1) {
2897 xmlGenericError(xmlGenericErrorContext,
2898 "element content for %s is compilable\n",
2899 def->name);
2900 } else if (ret == 0) {
2901 xmlGenericError(xmlGenericErrorContext,
2902 "element content for %s is not compilable\n",
2903 def->name);
2904 } else {
2905 xmlGenericError(xmlGenericErrorContext,
2906 "Problem in RelaxNGIsCompileable for element %s\n",
2907 def->name);
2908 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002909#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002910 }
2911 /*
2912 * All elements return a compileable status unless they
2913 * are generic like anyName
2914 */
2915 if ((def->nameClass != NULL) || (def->name == NULL))
2916 ret = 0;
2917 else
2918 ret = 1;
2919 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002920 case XML_RELAXNG_REF:
2921 case XML_RELAXNG_EXTERNALREF:
2922 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002923 if (def->depth == -20) {
2924 return (1);
2925 } else {
2926 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002927
Daniel Veillard4c004142003-10-07 11:33:24 +00002928 def->depth = -20;
2929 list = def->content;
2930 while (list != NULL) {
2931 ret = xmlRelaxNGIsCompileable(list);
2932 if (ret != 1)
2933 break;
2934 list = list->next;
2935 }
2936 }
2937 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002938 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002939 case XML_RELAXNG_OPTIONAL:
2940 case XML_RELAXNG_ZEROORMORE:
2941 case XML_RELAXNG_ONEORMORE:
2942 case XML_RELAXNG_CHOICE:
2943 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002944 case XML_RELAXNG_DEF:{
2945 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002946
Daniel Veillard4c004142003-10-07 11:33:24 +00002947 list = def->content;
2948 while (list != NULL) {
2949 ret = xmlRelaxNGIsCompileable(list);
2950 if (ret != 1)
2951 break;
2952 list = list->next;
2953 }
2954 break;
2955 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002956 case XML_RELAXNG_EXCEPT:
2957 case XML_RELAXNG_ATTRIBUTE:
2958 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002959 case XML_RELAXNG_DATATYPE:
2960 case XML_RELAXNG_LIST:
2961 case XML_RELAXNG_PARAM:
2962 case XML_RELAXNG_VALUE:
Daniel Veillard952379b2003-03-17 15:37:12 +00002963 case XML_RELAXNG_NOT_ALLOWED:
William M. Brack7e29c0a2004-04-02 09:07:22 +00002964 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002965 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002966 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002967 if (ret == 0)
2968 def->dflags |= IS_NOT_COMPILABLE;
2969 if (ret == 1)
2970 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002971#ifdef DEBUG_COMPILE
2972 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002973 xmlGenericError(xmlGenericErrorContext,
2974 "RelaxNGIsCompileable %s : true\n",
2975 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002976 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002977 xmlGenericError(xmlGenericErrorContext,
2978 "RelaxNGIsCompileable %s : false\n",
2979 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002980 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002981 xmlGenericError(xmlGenericErrorContext,
2982 "Problem in RelaxNGIsCompileable %s\n",
2983 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002984 }
2985#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002986 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002987}
2988
2989/**
2990 * xmlRelaxNGCompile:
2991 * ctxt: the RelaxNG parser context
2992 * @define: the definition tree to compile
2993 *
2994 * Compile the set of definitions, it works recursively, till the
2995 * element boundaries, where it tries to compile the content if possible
2996 *
2997 * Returns 0 if success and -1 in case of error
2998 */
2999static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003000xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3001{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003002 int ret = 0;
3003 xmlRelaxNGDefinePtr list;
3004
Daniel Veillard4c004142003-10-07 11:33:24 +00003005 if ((ctxt == NULL) || (def == NULL))
3006 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003007
Daniel Veillard4c004142003-10-07 11:33:24 +00003008 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003009 case XML_RELAXNG_START:
3010 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003011 xmlAutomataPtr oldam = ctxt->am;
3012 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003013
3014 def->depth = -25;
3015
Daniel Veillard4c004142003-10-07 11:33:24 +00003016 list = def->content;
3017 ctxt->am = xmlNewAutomata();
3018 if (ctxt->am == NULL)
3019 return (-1);
3020 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3021 while (list != NULL) {
3022 xmlRelaxNGCompile(ctxt, list);
3023 list = list->next;
3024 }
3025 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3026 def->contModel = xmlAutomataCompile(ctxt->am);
3027 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003028
Daniel Veillard4c004142003-10-07 11:33:24 +00003029 xmlFreeAutomata(ctxt->am);
3030 ctxt->state = oldstate;
3031 ctxt->am = oldam;
3032 }
3033 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003034 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003035 if ((ctxt->am != NULL) && (def->name != NULL)) {
3036 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3037 ctxt->state, NULL,
3038 def->name, def->ns,
3039 def);
3040 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003041 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003042 xmlAutomataPtr oldam = ctxt->am;
3043 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003044
3045 def->depth = -25;
3046
Daniel Veillard4c004142003-10-07 11:33:24 +00003047 list = def->content;
3048 ctxt->am = xmlNewAutomata();
3049 if (ctxt->am == NULL)
3050 return (-1);
3051 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3052 while (list != NULL) {
3053 xmlRelaxNGCompile(ctxt, list);
3054 list = list->next;
3055 }
3056 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3057 def->contModel = xmlAutomataCompile(ctxt->am);
3058 if (!xmlRegexpIsDeterminist(def->contModel)) {
3059 /*
3060 * we can only use the automata if it is determinist
3061 */
3062 xmlRegFreeRegexp(def->contModel);
3063 def->contModel = NULL;
3064 }
3065 xmlFreeAutomata(ctxt->am);
3066 ctxt->state = oldstate;
3067 ctxt->am = oldam;
3068 } else {
3069 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003070
Daniel Veillard4c004142003-10-07 11:33:24 +00003071 /*
3072 * we can't build the content model for this element content
3073 * but it still might be possible to build it for some of its
3074 * children, recurse.
3075 */
3076 ret = xmlRelaxNGTryCompile(ctxt, def);
3077 ctxt->am = oldam;
3078 }
3079 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003080 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003081 ret = xmlRelaxNGCompile(ctxt, def->content);
3082 break;
3083 case XML_RELAXNG_OPTIONAL:{
3084 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003085
Daniel Veillard4c004142003-10-07 11:33:24 +00003086 xmlRelaxNGCompile(ctxt, def->content);
3087 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3088 break;
3089 }
3090 case XML_RELAXNG_ZEROORMORE:{
3091 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003092
Daniel Veillard4c004142003-10-07 11:33:24 +00003093 ctxt->state =
3094 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3095 oldstate = ctxt->state;
3096 list = def->content;
3097 while (list != NULL) {
3098 xmlRelaxNGCompile(ctxt, list);
3099 list = list->next;
3100 }
3101 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3102 ctxt->state =
3103 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3104 break;
3105 }
3106 case XML_RELAXNG_ONEORMORE:{
3107 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003108
Daniel Veillard4c004142003-10-07 11:33:24 +00003109 list = def->content;
3110 while (list != NULL) {
3111 xmlRelaxNGCompile(ctxt, list);
3112 list = list->next;
3113 }
3114 oldstate = ctxt->state;
3115 list = def->content;
3116 while (list != NULL) {
3117 xmlRelaxNGCompile(ctxt, list);
3118 list = list->next;
3119 }
3120 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3121 ctxt->state =
3122 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3123 break;
3124 }
3125 case XML_RELAXNG_CHOICE:{
3126 xmlAutomataStatePtr target = NULL;
3127 xmlAutomataStatePtr oldstate = ctxt->state;
3128
3129 list = def->content;
3130 while (list != NULL) {
3131 ctxt->state = oldstate;
3132 ret = xmlRelaxNGCompile(ctxt, list);
3133 if (ret != 0)
3134 break;
3135 if (target == NULL)
3136 target = ctxt->state;
3137 else {
3138 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3139 target);
3140 }
3141 list = list->next;
3142 }
3143 ctxt->state = target;
3144
3145 break;
3146 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003147 case XML_RELAXNG_REF:
3148 case XML_RELAXNG_EXTERNALREF:
3149 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003150 case XML_RELAXNG_GROUP:
3151 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003152 list = def->content;
3153 while (list != NULL) {
3154 ret = xmlRelaxNGCompile(ctxt, list);
3155 if (ret != 0)
3156 break;
3157 list = list->next;
3158 }
3159 break;
3160 case XML_RELAXNG_TEXT:{
3161 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003162
Daniel Veillard4c004142003-10-07 11:33:24 +00003163 ctxt->state =
3164 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3165 oldstate = ctxt->state;
3166 xmlRelaxNGCompile(ctxt, def->content);
3167 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3168 ctxt->state, BAD_CAST "#text",
3169 NULL);
3170 ctxt->state =
3171 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3172 break;
3173 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003174 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003175 ctxt->state =
3176 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3177 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003178 case XML_RELAXNG_EXCEPT:
3179 case XML_RELAXNG_ATTRIBUTE:
3180 case XML_RELAXNG_INTERLEAVE:
3181 case XML_RELAXNG_NOT_ALLOWED:
3182 case XML_RELAXNG_DATATYPE:
3183 case XML_RELAXNG_LIST:
3184 case XML_RELAXNG_PARAM:
3185 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003186 /* This should not happen and generate an internal error */
3187 fprintf(stderr, "RNG internal error trying to compile %s\n",
3188 xmlRelaxNGDefName(def));
3189 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003190 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003191 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003192}
3193
3194/**
3195 * xmlRelaxNGTryCompile:
3196 * ctxt: the RelaxNG parser context
3197 * @define: the definition tree to compile
3198 *
3199 * Try to compile the set of definitions, it works recursively,
3200 * possibly ignoring parts which cannot be compiled.
3201 *
3202 * Returns 0 if success and -1 in case of error
3203 */
3204static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003205xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3206{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003207 int ret = 0;
3208 xmlRelaxNGDefinePtr list;
3209
Daniel Veillard4c004142003-10-07 11:33:24 +00003210 if ((ctxt == NULL) || (def == NULL))
3211 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003212
3213 if ((def->type == XML_RELAXNG_START) ||
3214 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003215 ret = xmlRelaxNGIsCompileable(def);
3216 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3217 ctxt->am = NULL;
3218 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003219#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003220 if (ret == 0) {
3221 if (def->type == XML_RELAXNG_START)
3222 xmlGenericError(xmlGenericErrorContext,
3223 "compiled the start\n");
3224 else
3225 xmlGenericError(xmlGenericErrorContext,
3226 "compiled element %s\n", def->name);
3227 } else {
3228 if (def->type == XML_RELAXNG_START)
3229 xmlGenericError(xmlGenericErrorContext,
3230 "failed to compile the start\n");
3231 else
3232 xmlGenericError(xmlGenericErrorContext,
3233 "failed to compile element %s\n",
3234 def->name);
3235 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003236#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003237 return (ret);
3238 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003239 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003240 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003241 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003242 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3243 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003244 case XML_RELAXNG_TEXT:
3245 case XML_RELAXNG_DATATYPE:
3246 case XML_RELAXNG_LIST:
3247 case XML_RELAXNG_PARAM:
3248 case XML_RELAXNG_VALUE:
3249 case XML_RELAXNG_EMPTY:
3250 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003251 ret = 0;
3252 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003253 case XML_RELAXNG_OPTIONAL:
3254 case XML_RELAXNG_ZEROORMORE:
3255 case XML_RELAXNG_ONEORMORE:
3256 case XML_RELAXNG_CHOICE:
3257 case XML_RELAXNG_GROUP:
3258 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003259 case XML_RELAXNG_START:
3260 case XML_RELAXNG_REF:
3261 case XML_RELAXNG_EXTERNALREF:
3262 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003263 list = def->content;
3264 while (list != NULL) {
3265 ret = xmlRelaxNGTryCompile(ctxt, list);
3266 if (ret != 0)
3267 break;
3268 list = list->next;
3269 }
3270 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003271 case XML_RELAXNG_EXCEPT:
3272 case XML_RELAXNG_ATTRIBUTE:
3273 case XML_RELAXNG_INTERLEAVE:
3274 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003275 ret = 0;
3276 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003277 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003278 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003279}
3280
3281/************************************************************************
3282 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003283 * Parsing functions *
3284 * *
3285 ************************************************************************/
3286
Daniel Veillard4c004142003-10-07 11:33:24 +00003287static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3288 ctxt, xmlNodePtr node);
3289static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3290 ctxt, xmlNodePtr node);
3291static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3292 ctxt, xmlNodePtr nodes,
3293 int group);
3294static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3295 ctxt, xmlNodePtr node);
3296static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3297 xmlNodePtr node);
3298static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3299 xmlNodePtr nodes);
3300static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3301 ctxt, xmlNodePtr node,
3302 xmlRelaxNGDefinePtr
3303 def);
3304static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3305 ctxt, xmlNodePtr nodes);
3306static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3307 xmlRelaxNGDefinePtr define,
3308 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003309
3310
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003311#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003312
3313/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003314 * xmlRelaxNGIsNullable:
3315 * @define: the definition to verify
3316 *
3317 * Check if a definition is nullable.
3318 *
3319 * Returns 1 if yes, 0 if no and -1 in case of error
3320 */
3321static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003322xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3323{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003324 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003325
Daniel Veillardfd573f12003-03-16 17:52:32 +00003326 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003327 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003328
Daniel Veillarde063f482003-03-21 16:53:17 +00003329 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003330 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003331 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003332 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003333 switch (define->type) {
3334 case XML_RELAXNG_EMPTY:
3335 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003336 ret = 1;
3337 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003338 case XML_RELAXNG_NOOP:
3339 case XML_RELAXNG_DEF:
3340 case XML_RELAXNG_REF:
3341 case XML_RELAXNG_EXTERNALREF:
3342 case XML_RELAXNG_PARENTREF:
3343 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003344 ret = xmlRelaxNGIsNullable(define->content);
3345 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003346 case XML_RELAXNG_EXCEPT:
3347 case XML_RELAXNG_NOT_ALLOWED:
3348 case XML_RELAXNG_ELEMENT:
3349 case XML_RELAXNG_DATATYPE:
3350 case XML_RELAXNG_PARAM:
3351 case XML_RELAXNG_VALUE:
3352 case XML_RELAXNG_LIST:
3353 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003354 ret = 0;
3355 break;
3356 case XML_RELAXNG_CHOICE:{
3357 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003358
Daniel Veillard4c004142003-10-07 11:33:24 +00003359 while (list != NULL) {
3360 ret = xmlRelaxNGIsNullable(list);
3361 if (ret != 0)
3362 goto done;
3363 list = list->next;
3364 }
3365 ret = 0;
3366 break;
3367 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003368 case XML_RELAXNG_START:
3369 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003370 case XML_RELAXNG_GROUP:{
3371 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003372
Daniel Veillard4c004142003-10-07 11:33:24 +00003373 while (list != NULL) {
3374 ret = xmlRelaxNGIsNullable(list);
3375 if (ret != 1)
3376 goto done;
3377 list = list->next;
3378 }
3379 return (1);
3380 }
3381 default:
3382 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003383 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003384 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003385 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003386 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003387 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003388 define->dflags |= IS_NULLABLE;
3389 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003390}
3391
3392/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003393 * xmlRelaxNGIsBlank:
3394 * @str: a string
3395 *
3396 * Check if a string is ignorable c.f. 4.2. Whitespace
3397 *
3398 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3399 */
3400static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003401xmlRelaxNGIsBlank(xmlChar * str)
3402{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003403 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003404 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003405 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003406 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003407 return (0);
3408 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003409 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003410 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003411}
3412
Daniel Veillard6eadf632003-01-23 18:29:16 +00003413/**
3414 * xmlRelaxNGGetDataTypeLibrary:
3415 * @ctxt: a Relax-NG parser context
3416 * @node: the current data or value element
3417 *
3418 * Applies algorithm from 4.3. datatypeLibrary attribute
3419 *
3420 * Returns the datatypeLibary value or NULL if not found
3421 */
3422static xmlChar *
3423xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003424 xmlNodePtr node)
3425{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003426 xmlChar *ret, *escape;
3427
Daniel Veillard6eadf632003-01-23 18:29:16 +00003428 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003429 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3430 if (ret != NULL) {
3431 if (ret[0] == 0) {
3432 xmlFree(ret);
3433 return (NULL);
3434 }
3435 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3436 if (escape == NULL) {
3437 return (ret);
3438 }
3439 xmlFree(ret);
3440 return (escape);
3441 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003442 }
3443 node = node->parent;
3444 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003445 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3446 if (ret != NULL) {
3447 if (ret[0] == 0) {
3448 xmlFree(ret);
3449 return (NULL);
3450 }
3451 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3452 if (escape == NULL) {
3453 return (ret);
3454 }
3455 xmlFree(ret);
3456 return (escape);
3457 }
3458 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003459 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003460 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003461}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003462
3463/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003464 * xmlRelaxNGParseValue:
3465 * @ctxt: a Relax-NG parser context
3466 * @node: the data node.
3467 *
3468 * parse the content of a RelaxNG value node.
3469 *
3470 * Returns the definition pointer or NULL in case of error
3471 */
3472static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003473xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3474{
Daniel Veillardedc91922003-01-26 00:52:04 +00003475 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003476 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003477 xmlChar *type;
3478 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003479 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003480
Daniel Veillardfd573f12003-03-16 17:52:32 +00003481 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003482 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003483 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003484 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003485
3486 type = xmlGetProp(node, BAD_CAST "type");
3487 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003488 xmlRelaxNGNormExtSpace(type);
3489 if (xmlValidateNCName(type, 0)) {
3490 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3491 "value type '%s' is not an NCName\n", type, NULL);
3492 }
3493 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3494 if (library == NULL)
3495 library =
3496 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003497
Daniel Veillard4c004142003-10-07 11:33:24 +00003498 def->name = type;
3499 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003500
Daniel Veillard4c004142003-10-07 11:33:24 +00003501 lib = (xmlRelaxNGTypeLibraryPtr)
3502 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3503 if (lib == NULL) {
3504 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3505 "Use of unregistered type library '%s'\n", library,
3506 NULL);
3507 def->data = NULL;
3508 } else {
3509 def->data = lib;
3510 if (lib->have == NULL) {
3511 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3512 "Internal error with type library '%s': no 'have'\n",
3513 library, NULL);
3514 } else {
3515 success = lib->have(lib->data, def->name);
3516 if (success != 1) {
3517 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3518 "Error type '%s' is not exported by type library '%s'\n",
3519 def->name, library);
3520 }
3521 }
3522 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003523 }
3524 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003525 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003526 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003527 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3528 (node->children->next != NULL)) {
3529 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3530 "Expecting a single text value for <value>content\n",
3531 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003532 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003533 def->value = xmlNodeGetContent(node);
3534 if (def->value == NULL) {
3535 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3536 "Element <value> has no content\n", NULL, NULL);
3537 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3538 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003539
Daniel Veillard4c004142003-10-07 11:33:24 +00003540 success =
3541 lib->check(lib->data, def->name, def->value, &val, node);
3542 if (success != 1) {
3543 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3544 "Value '%s' is not acceptable for type '%s'\n",
3545 def->value, def->name);
3546 } else {
3547 if (val != NULL)
3548 def->attrs = val;
3549 }
3550 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003551 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003552 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003553}
3554
3555/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003556 * xmlRelaxNGParseData:
3557 * @ctxt: a Relax-NG parser context
3558 * @node: the data node.
3559 *
3560 * parse the content of a RelaxNG data node.
3561 *
3562 * Returns the definition pointer or NULL in case of error
3563 */
3564static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003565xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3566{
Daniel Veillard416589a2003-02-17 17:25:42 +00003567 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003568 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003569 xmlRelaxNGTypeLibraryPtr lib;
3570 xmlChar *type;
3571 xmlChar *library;
3572 xmlNodePtr content;
3573 int tmp;
3574
3575 type = xmlGetProp(node, BAD_CAST "type");
3576 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003577 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3578 NULL);
3579 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003580 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003581 xmlRelaxNGNormExtSpace(type);
3582 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003583 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3584 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003585 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003586 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3587 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003588 library =
3589 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003590
Daniel Veillardfd573f12003-03-16 17:52:32 +00003591 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003592 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003593 xmlFree(type);
3594 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003595 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003596 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003597 def->name = type;
3598 def->ns = library;
3599
3600 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003601 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003602 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003603 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3604 "Use of unregistered type library '%s'\n", library,
3605 NULL);
3606 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003607 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003608 def->data = lib;
3609 if (lib->have == NULL) {
3610 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3611 "Internal error with type library '%s': no 'have'\n",
3612 library, NULL);
3613 } else {
3614 tmp = lib->have(lib->data, def->name);
3615 if (tmp != 1) {
3616 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3617 "Error type '%s' is not exported by type library '%s'\n",
3618 def->name, library);
3619 } else
3620 if ((xmlStrEqual
3621 (library,
3622 BAD_CAST
3623 "http://www.w3.org/2001/XMLSchema-datatypes"))
3624 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3625 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3626 ctxt->idref = 1;
3627 }
3628 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003629 }
3630 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003631
3632 /*
3633 * Handle optional params
3634 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003635 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003636 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3637 break;
3638 if (xmlStrEqual(library,
3639 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3640 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3641 "Type library '%s' does not allow type parameters\n",
3642 library, NULL);
3643 content = content->next;
3644 while ((content != NULL) &&
3645 (xmlStrEqual(content->name, BAD_CAST "param")))
3646 content = content->next;
3647 } else {
3648 param = xmlRelaxNGNewDefine(ctxt, node);
3649 if (param != NULL) {
3650 param->type = XML_RELAXNG_PARAM;
3651 param->name = xmlGetProp(content, BAD_CAST "name");
3652 if (param->name == NULL) {
3653 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3654 "param has no name\n", NULL, NULL);
3655 }
3656 param->value = xmlNodeGetContent(content);
3657 if (lastparam == NULL) {
3658 def->attrs = lastparam = param;
3659 } else {
3660 lastparam->next = param;
3661 lastparam = param;
3662 }
3663 if (lib != NULL) {
3664 }
3665 }
3666 content = content->next;
3667 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003668 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003669 /*
3670 * Handle optional except
3671 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003672 if ((content != NULL)
3673 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3674 xmlNodePtr child;
3675 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003676
Daniel Veillard4c004142003-10-07 11:33:24 +00003677 except = xmlRelaxNGNewDefine(ctxt, node);
3678 if (except == NULL) {
3679 return (def);
3680 }
3681 except->type = XML_RELAXNG_EXCEPT;
3682 child = content->children;
3683 if (last == NULL) {
3684 def->content = except;
3685 } else {
3686 last->next = except;
3687 }
3688 if (child == NULL) {
3689 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3690 "except has no content\n", NULL, NULL);
3691 }
3692 while (child != NULL) {
3693 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3694 if (tmp2 != NULL) {
3695 if (last2 == NULL) {
3696 except->content = last2 = tmp2;
3697 } else {
3698 last2->next = tmp2;
3699 last2 = tmp2;
3700 }
3701 }
3702 child = child->next;
3703 }
3704 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003705 }
3706 /*
3707 * Check there is no unhandled data
3708 */
3709 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003710 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3711 "Element data has unexpected content %s\n",
3712 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003713 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003714
Daniel Veillard4c004142003-10-07 11:33:24 +00003715 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003716}
3717
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003718static const xmlChar *invalidName = BAD_CAST "\1";
3719
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003720/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003721 * xmlRelaxNGCompareNameClasses:
3722 * @defs1: the first element/attribute defs
3723 * @defs2: the second element/attribute defs
3724 * @name: the restriction on the name
3725 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003726 *
3727 * Compare the 2 lists of element definitions. The comparison is
3728 * that if both lists do not accept the same QNames, it returns 1
3729 * If the 2 lists can accept the same QName the comparison returns 0
3730 *
3731 * Returns 1 disttinct, 0 if equal
3732 */
3733static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003734xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003735 xmlRelaxNGDefinePtr def2)
3736{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003737 int ret = 1;
3738 xmlNode node;
3739 xmlNs ns;
3740 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003741
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003742 ctxt.flags = FLAGS_IGNORABLE;
3743
Daniel Veillard42f12e92003-03-07 18:32:59 +00003744 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3745
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003746 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003747 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3748 if (def2->type == XML_RELAXNG_TEXT)
3749 return (1);
3750 if (def1->name != NULL) {
3751 node.name = def1->name;
3752 } else {
3753 node.name = invalidName;
3754 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003755 if (def1->ns != NULL) {
3756 if (def1->ns[0] == 0) {
3757 node.ns = NULL;
3758 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003759 node.ns = &ns;
Daniel Veillard4c004142003-10-07 11:33:24 +00003760 ns.href = def1->ns;
3761 }
3762 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003763 node.ns = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00003764 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003765 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003766 if (def1->nameClass != NULL) {
3767 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3768 } else {
3769 ret = 0;
3770 }
3771 } else {
3772 ret = 1;
3773 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003774 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003775 if (def2->type == XML_RELAXNG_TEXT)
3776 return (0);
3777 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003778 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003779 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003780 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003781 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003782 }
3783 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003784 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003785 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003786 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3787 if (def2->name != NULL) {
3788 node.name = def2->name;
3789 } else {
3790 node.name = invalidName;
3791 }
3792 node.ns = &ns;
3793 if (def2->ns != NULL) {
3794 if (def2->ns[0] == 0) {
3795 node.ns = NULL;
3796 } else {
3797 ns.href = def2->ns;
3798 }
3799 } else {
3800 ns.href = invalidName;
3801 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003802 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003803 if (def2->nameClass != NULL) {
3804 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3805 } else {
3806 ret = 0;
3807 }
3808 } else {
3809 ret = 1;
3810 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003811 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003812 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003813 }
3814
Daniel Veillard4c004142003-10-07 11:33:24 +00003815 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003816}
3817
3818/**
3819 * xmlRelaxNGCompareElemDefLists:
3820 * @ctxt: a Relax-NG parser context
3821 * @defs1: the first list of element/attribute defs
3822 * @defs2: the second list of element/attribute defs
3823 *
3824 * Compare the 2 lists of element or attribute definitions. The comparison
3825 * is that if both lists do not accept the same QNames, it returns 1
3826 * If the 2 lists can accept the same QName the comparison returns 0
3827 *
3828 * Returns 1 disttinct, 0 if equal
3829 */
3830static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003831xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3832 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3833 xmlRelaxNGDefinePtr * def2)
3834{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003835 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003836
Daniel Veillard154877e2003-01-30 12:17:05 +00003837 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003838 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003839 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003840 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003841 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003842 while ((*def2) != NULL) {
3843 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3844 return (0);
3845 def2++;
3846 }
3847 def2 = basedef2;
3848 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003849 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003850 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003851}
3852
3853/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003854 * xmlRelaxNGGenerateAttributes:
3855 * @ctxt: a Relax-NG parser context
3856 * @def: the definition definition
3857 *
3858 * Check if the definition can only generate attributes
3859 *
3860 * Returns 1 if yes, 0 if no and -1 in case of error.
3861 */
3862static int
3863xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003864 xmlRelaxNGDefinePtr def)
3865{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003866 xmlRelaxNGDefinePtr parent, cur, tmp;
3867
3868 /*
3869 * Don't run that check in case of error. Infinite recursion
3870 * becomes possible.
3871 */
3872 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003873 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003874
3875 parent = NULL;
3876 cur = def;
3877 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003878 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3879 (cur->type == XML_RELAXNG_TEXT) ||
3880 (cur->type == XML_RELAXNG_DATATYPE) ||
3881 (cur->type == XML_RELAXNG_PARAM) ||
3882 (cur->type == XML_RELAXNG_LIST) ||
3883 (cur->type == XML_RELAXNG_VALUE) ||
3884 (cur->type == XML_RELAXNG_EMPTY))
3885 return (0);
3886 if ((cur->type == XML_RELAXNG_CHOICE) ||
3887 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3888 (cur->type == XML_RELAXNG_GROUP) ||
3889 (cur->type == XML_RELAXNG_ONEORMORE) ||
3890 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3891 (cur->type == XML_RELAXNG_OPTIONAL) ||
3892 (cur->type == XML_RELAXNG_PARENTREF) ||
3893 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3894 (cur->type == XML_RELAXNG_REF) ||
3895 (cur->type == XML_RELAXNG_DEF)) {
3896 if (cur->content != NULL) {
3897 parent = cur;
3898 cur = cur->content;
3899 tmp = cur;
3900 while (tmp != NULL) {
3901 tmp->parent = parent;
3902 tmp = tmp->next;
3903 }
3904 continue;
3905 }
3906 }
3907 if (cur == def)
3908 break;
3909 if (cur->next != NULL) {
3910 cur = cur->next;
3911 continue;
3912 }
3913 do {
3914 cur = cur->parent;
3915 if (cur == NULL)
3916 break;
3917 if (cur == def)
3918 return (1);
3919 if (cur->next != NULL) {
3920 cur = cur->next;
3921 break;
3922 }
3923 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003924 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003925 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003926}
Daniel Veillard4c004142003-10-07 11:33:24 +00003927
Daniel Veillardce192eb2003-04-16 15:58:05 +00003928/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003929 * xmlRelaxNGGetElements:
3930 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003931 * @def: the definition definition
3932 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003933 *
3934 * Compute the list of top elements a definition can generate
3935 *
3936 * Returns a list of elements or NULL if none was found.
3937 */
3938static xmlRelaxNGDefinePtr *
3939xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003940 xmlRelaxNGDefinePtr def, int eora)
3941{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003942 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003943 int len = 0;
3944 int max = 0;
3945
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003946 /*
3947 * Don't run that check in case of error. Infinite recursion
3948 * becomes possible.
3949 */
3950 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003951 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003952
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003953 parent = NULL;
3954 cur = def;
3955 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003956 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3957 (cur->type == XML_RELAXNG_TEXT))) ||
3958 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3959 if (ret == NULL) {
3960 max = 10;
3961 ret = (xmlRelaxNGDefinePtr *)
3962 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3963 if (ret == NULL) {
3964 xmlRngPErrMemory(ctxt, "getting element list\n");
3965 return (NULL);
3966 }
3967 } else if (max <= len) {
Daniel Veillard079f6a72004-09-23 13:15:03 +00003968 xmlRelaxNGDefinePtr *temp;
3969
Daniel Veillard4c004142003-10-07 11:33:24 +00003970 max *= 2;
Daniel Veillard079f6a72004-09-23 13:15:03 +00003971 temp = xmlRealloc(ret,
Daniel Veillard4c004142003-10-07 11:33:24 +00003972 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
Daniel Veillard079f6a72004-09-23 13:15:03 +00003973 if (temp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003974 xmlRngPErrMemory(ctxt, "getting element list\n");
Daniel Veillard079f6a72004-09-23 13:15:03 +00003975 xmlFree(ret);
Daniel Veillard4c004142003-10-07 11:33:24 +00003976 return (NULL);
3977 }
Daniel Veillard079f6a72004-09-23 13:15:03 +00003978 ret = temp;
Daniel Veillard4c004142003-10-07 11:33:24 +00003979 }
3980 ret[len++] = cur;
3981 ret[len] = NULL;
3982 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3983 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3984 (cur->type == XML_RELAXNG_GROUP) ||
3985 (cur->type == XML_RELAXNG_ONEORMORE) ||
3986 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3987 (cur->type == XML_RELAXNG_OPTIONAL) ||
3988 (cur->type == XML_RELAXNG_PARENTREF) ||
3989 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00003990 (cur->type == XML_RELAXNG_DEF) ||
3991 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003992 /*
3993 * Don't go within elements or attributes or string values.
3994 * Just gather the element top list
3995 */
3996 if (cur->content != NULL) {
3997 parent = cur;
3998 cur = cur->content;
3999 tmp = cur;
4000 while (tmp != NULL) {
4001 tmp->parent = parent;
4002 tmp = tmp->next;
4003 }
4004 continue;
4005 }
4006 }
4007 if (cur == def)
4008 break;
4009 if (cur->next != NULL) {
4010 cur = cur->next;
4011 continue;
4012 }
4013 do {
4014 cur = cur->parent;
4015 if (cur == NULL)
4016 break;
4017 if (cur == def)
4018 return (ret);
4019 if (cur->next != NULL) {
4020 cur = cur->next;
4021 break;
4022 }
4023 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004024 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004025 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004026}
Daniel Veillard4c004142003-10-07 11:33:24 +00004027
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004028/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004029 * xmlRelaxNGCheckChoiceDeterminism:
4030 * @ctxt: a Relax-NG parser context
4031 * @def: the choice definition
4032 *
4033 * Also used to find indeterministic pattern in choice
4034 */
4035static void
4036xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004037 xmlRelaxNGDefinePtr def)
4038{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004039 xmlRelaxNGDefinePtr **list;
4040 xmlRelaxNGDefinePtr cur;
4041 int nbchild = 0, i, j, ret;
4042 int is_nullable = 0;
4043 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004044 xmlHashTablePtr triage = NULL;
4045 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004046
Daniel Veillard4c004142003-10-07 11:33:24 +00004047 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4048 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004049
Daniel Veillarde063f482003-03-21 16:53:17 +00004050 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004051 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004052
Daniel Veillardfd573f12003-03-16 17:52:32 +00004053 /*
4054 * Don't run that check in case of error. Infinite recursion
4055 * becomes possible.
4056 */
4057 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004058 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004059
4060 is_nullable = xmlRelaxNGIsNullable(def);
4061
4062 cur = def->content;
4063 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004064 nbchild++;
4065 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004066 }
4067
4068 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004069 sizeof(xmlRelaxNGDefinePtr
4070 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004071 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004072 xmlRngPErrMemory(ctxt, "building choice\n");
4073 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004074 }
4075 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004076 /*
4077 * a bit strong but safe
4078 */
4079 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004080 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004081 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004082 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004083 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004084 cur = def->content;
4085 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004086 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4087 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4088 is_triable = 0;
4089 } else if (is_triable == 1) {
4090 xmlRelaxNGDefinePtr *tmp;
4091 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004092
Daniel Veillard4c004142003-10-07 11:33:24 +00004093 tmp = list[i];
4094 while ((*tmp != NULL) && (is_triable == 1)) {
4095 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4096 res = xmlHashAddEntry2(triage,
4097 BAD_CAST "#text", NULL,
4098 (void *) cur);
4099 if (res != 0)
4100 is_triable = -1;
4101 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4102 ((*tmp)->name != NULL)) {
4103 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4104 res = xmlHashAddEntry2(triage,
4105 (*tmp)->name, NULL,
4106 (void *) cur);
4107 else
4108 res = xmlHashAddEntry2(triage,
4109 (*tmp)->name, (*tmp)->ns,
4110 (void *) cur);
4111 if (res != 0)
4112 is_triable = -1;
4113 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4114 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4115 res = xmlHashAddEntry2(triage,
4116 BAD_CAST "#any", NULL,
4117 (void *) cur);
4118 else
4119 res = xmlHashAddEntry2(triage,
4120 BAD_CAST "#any", (*tmp)->ns,
4121 (void *) cur);
4122 if (res != 0)
4123 is_triable = -1;
4124 } else {
4125 is_triable = -1;
4126 }
4127 tmp++;
4128 }
4129 }
4130 i++;
4131 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004132 }
4133
Daniel Veillard4c004142003-10-07 11:33:24 +00004134 for (i = 0; i < nbchild; i++) {
4135 if (list[i] == NULL)
4136 continue;
4137 for (j = 0; j < i; j++) {
4138 if (list[j] == NULL)
4139 continue;
4140 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4141 if (ret == 0) {
4142 is_indeterminist = 1;
4143 }
4144 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004145 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004146 for (i = 0; i < nbchild; i++) {
4147 if (list[i] != NULL)
4148 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004149 }
4150
4151 xmlFree(list);
4152 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004153 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004154 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004155 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004156 def->dflags |= IS_TRIABLE;
4157 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004158 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004159 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004160 }
4161 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162}
4163
4164/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004165 * xmlRelaxNGCheckGroupAttrs:
4166 * @ctxt: a Relax-NG parser context
4167 * @def: the group definition
4168 *
4169 * Detects violations of rule 7.3
4170 */
4171static void
4172xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004173 xmlRelaxNGDefinePtr def)
4174{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004175 xmlRelaxNGDefinePtr **list;
4176 xmlRelaxNGDefinePtr cur;
4177 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004178
4179 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004180 ((def->type != XML_RELAXNG_GROUP) &&
4181 (def->type != XML_RELAXNG_ELEMENT)))
4182 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004183
Daniel Veillarde063f482003-03-21 16:53:17 +00004184 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004185 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004186
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004187 /*
4188 * Don't run that check in case of error. Infinite recursion
4189 * becomes possible.
4190 */
4191 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004192 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004193
Daniel Veillardfd573f12003-03-16 17:52:32 +00004194 cur = def->attrs;
4195 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004196 nbchild++;
4197 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004198 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004199 cur = def->content;
4200 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004201 nbchild++;
4202 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004203 }
4204
4205 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004206 sizeof(xmlRelaxNGDefinePtr
4207 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004208 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004209 xmlRngPErrMemory(ctxt, "building group\n");
4210 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004211 }
4212 i = 0;
4213 cur = def->attrs;
4214 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004215 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4216 i++;
4217 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004218 }
4219 cur = def->content;
4220 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004221 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4222 i++;
4223 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004224 }
4225
Daniel Veillard4c004142003-10-07 11:33:24 +00004226 for (i = 0; i < nbchild; i++) {
4227 if (list[i] == NULL)
4228 continue;
4229 for (j = 0; j < i; j++) {
4230 if (list[j] == NULL)
4231 continue;
4232 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4233 if (ret == 0) {
4234 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4235 "Attributes conflicts in group\n", NULL, NULL);
4236 }
4237 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004238 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004239 for (i = 0; i < nbchild; i++) {
4240 if (list[i] != NULL)
4241 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004242 }
4243
4244 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004245 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004246}
4247
4248/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004249 * xmlRelaxNGComputeInterleaves:
4250 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004251 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004252 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004253 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004254 * A lot of work for preprocessing interleave definitions
4255 * is potentially needed to get a decent execution speed at runtime
4256 * - trying to get a total order on the element nodes generated
4257 * by the interleaves, order the list of interleave definitions
4258 * following that order.
4259 * - if <text/> is used to handle mixed content, it is better to
4260 * flag this in the define and simplify the runtime checking
4261 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004262 */
4263static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004264xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004265 xmlRelaxNGParserCtxtPtr ctxt,
4266 xmlChar * name ATTRIBUTE_UNUSED)
4267{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004268 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004269
Daniel Veillardfd573f12003-03-16 17:52:32 +00004270 xmlRelaxNGPartitionPtr partitions = NULL;
4271 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4272 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004273 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004274 int nbgroups = 0;
4275 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004276 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004277 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004278
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004279 /*
4280 * Don't run that check in case of error. Infinite recursion
4281 * becomes possible.
4282 */
4283 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004284 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004285
Daniel Veillardfd573f12003-03-16 17:52:32 +00004286#ifdef DEBUG_INTERLEAVE
4287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004288 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004289#endif
4290 cur = def->content;
4291 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004292 nbchild++;
4293 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004294 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004295
Daniel Veillardfd573f12003-03-16 17:52:32 +00004296#ifdef DEBUG_INTERLEAVE
4297 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4298#endif
4299 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004300 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004301 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004302 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004303 cur = def->content;
4304 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004305 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4306 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4307 if (groups[nbgroups] == NULL)
4308 goto error;
4309 if (cur->type == XML_RELAXNG_TEXT)
4310 is_mixed++;
4311 groups[nbgroups]->rule = cur;
4312 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4313 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4314 nbgroups++;
4315 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004316 }
4317#ifdef DEBUG_INTERLEAVE
4318 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4319#endif
4320
4321 /*
4322 * Let's check that all rules makes a partitions according to 7.4
4323 */
4324 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004325 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004326 if (partitions == NULL)
4327 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004328 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004329 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004330 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004331 for (i = 0; i < nbgroups; i++) {
4332 group = groups[i];
4333 for (j = i + 1; j < nbgroups; j++) {
4334 if (groups[j] == NULL)
4335 continue;
4336
4337 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4338 groups[j]->defs);
4339 if (ret == 0) {
4340 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4341 "Element or text conflicts in interleave\n",
4342 NULL, NULL);
4343 }
4344 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4345 groups[j]->attrs);
4346 if (ret == 0) {
4347 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4348 "Attributes conflicts in interleave\n", NULL,
4349 NULL);
4350 }
4351 }
4352 tmp = group->defs;
4353 if ((tmp != NULL) && (*tmp != NULL)) {
4354 while (*tmp != NULL) {
4355 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4356 res = xmlHashAddEntry2(partitions->triage,
4357 BAD_CAST "#text", NULL,
4358 (void *) (long) (i + 1));
4359 if (res != 0)
4360 is_determinist = -1;
4361 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4362 ((*tmp)->name != NULL)) {
4363 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4364 res = xmlHashAddEntry2(partitions->triage,
4365 (*tmp)->name, NULL,
4366 (void *) (long) (i + 1));
4367 else
4368 res = xmlHashAddEntry2(partitions->triage,
4369 (*tmp)->name, (*tmp)->ns,
4370 (void *) (long) (i + 1));
4371 if (res != 0)
4372 is_determinist = -1;
4373 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4374 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4375 res = xmlHashAddEntry2(partitions->triage,
4376 BAD_CAST "#any", NULL,
4377 (void *) (long) (i + 1));
4378 else
4379 res = xmlHashAddEntry2(partitions->triage,
4380 BAD_CAST "#any", (*tmp)->ns,
4381 (void *) (long) (i + 1));
4382 if ((*tmp)->nameClass != NULL)
4383 is_determinist = 2;
4384 if (res != 0)
4385 is_determinist = -1;
4386 } else {
4387 is_determinist = -1;
4388 }
4389 tmp++;
4390 }
4391 } else {
4392 is_determinist = 0;
4393 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004394 }
4395 partitions->groups = groups;
4396
4397 /*
4398 * and save the partition list back in the def
4399 */
4400 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004401 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004402 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004403 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004404 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004405 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004406 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004407 return;
4408
Daniel Veillard4c004142003-10-07 11:33:24 +00004409 error:
4410 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004411 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004412 for (i = 0; i < nbgroups; i++)
4413 if (groups[i] != NULL) {
4414 if (groups[i]->defs != NULL)
4415 xmlFree(groups[i]->defs);
4416 xmlFree(groups[i]);
4417 }
4418 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004419 }
4420 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004421}
4422
4423/**
4424 * xmlRelaxNGParseInterleave:
4425 * @ctxt: a Relax-NG parser context
4426 * @node: the data node.
4427 *
4428 * parse the content of a RelaxNG interleave node.
4429 *
4430 * Returns the definition pointer or NULL in case of error
4431 */
4432static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004433xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4434{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004435 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004436 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004437 xmlNodePtr child;
4438
Daniel Veillardfd573f12003-03-16 17:52:32 +00004439 def = xmlRelaxNGNewDefine(ctxt, node);
4440 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004441 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004442 }
4443 def->type = XML_RELAXNG_INTERLEAVE;
4444
4445 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004446 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004447 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004448 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004449 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004450 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004451
Daniel Veillard4c004142003-10-07 11:33:24 +00004452 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4453 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4454 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4455 "Failed to add %s to hash table\n",
4456 (const xmlChar *) name, NULL);
4457 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004458 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004459 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004460 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004461 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4462 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004463 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004464 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004465 if (IS_RELAXNG(child, "element")) {
4466 cur = xmlRelaxNGParseElement(ctxt, child);
4467 } else {
4468 cur = xmlRelaxNGParsePattern(ctxt, child);
4469 }
4470 if (cur != NULL) {
4471 cur->parent = def;
4472 if (last == NULL) {
4473 def->content = last = cur;
4474 } else {
4475 last->next = cur;
4476 last = cur;
4477 }
4478 }
4479 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 }
4481
Daniel Veillard4c004142003-10-07 11:33:24 +00004482 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004483}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004484
4485/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004486 * xmlRelaxNGParseInclude:
4487 * @ctxt: a Relax-NG parser context
4488 * @node: the include node
4489 *
4490 * Integrate the content of an include node in the current grammar
4491 *
4492 * Returns 0 in case of success or -1 in case of error
4493 */
4494static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004495xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4496{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004497 xmlRelaxNGIncludePtr incl;
4498 xmlNodePtr root;
4499 int ret = 0, tmp;
4500
Daniel Veillard807daf82004-02-22 22:13:27 +00004501 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004502 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004503 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4504 "Include node has no data\n", NULL, NULL);
4505 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004506 }
4507 root = xmlDocGetRootElement(incl->doc);
4508 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004509 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4510 NULL, NULL);
4511 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004512 }
4513 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004514 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4515 "Include document root is not a grammar\n", NULL, NULL);
4516 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004517 }
4518
4519 /*
4520 * Merge the definition from both the include and the internal list
4521 */
4522 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004523 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4524 if (tmp != 0)
4525 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004526 }
4527 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004528 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4529 if (tmp != 0)
4530 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004531 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004532 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004533}
4534
4535/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004536 * xmlRelaxNGParseDefine:
4537 * @ctxt: a Relax-NG parser context
4538 * @node: the define node
4539 *
4540 * parse the content of a RelaxNG define element node.
4541 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004542 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004543 */
4544static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004545xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4546{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004547 xmlChar *name;
4548 int ret = 0, tmp;
4549 xmlRelaxNGDefinePtr def;
4550 const xmlChar *olddefine;
4551
4552 name = xmlGetProp(node, BAD_CAST "name");
4553 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004554 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4555 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004556 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004557 xmlRelaxNGNormExtSpace(name);
4558 if (xmlValidateNCName(name, 0)) {
4559 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4560 "define name '%s' is not an NCName\n", name, NULL);
4561 }
4562 def = xmlRelaxNGNewDefine(ctxt, node);
4563 if (def == NULL) {
4564 xmlFree(name);
4565 return (-1);
4566 }
4567 def->type = XML_RELAXNG_DEF;
4568 def->name = name;
4569 if (node->children == NULL) {
4570 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4571 "define has no children\n", NULL, NULL);
4572 } else {
4573 olddefine = ctxt->define;
4574 ctxt->define = name;
4575 def->content =
4576 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4577 ctxt->define = olddefine;
4578 }
4579 if (ctxt->grammar->defs == NULL)
4580 ctxt->grammar->defs = xmlHashCreate(10);
4581 if (ctxt->grammar->defs == NULL) {
4582 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4583 "Could not create definition hash\n", NULL, NULL);
4584 ret = -1;
4585 } else {
4586 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4587 if (tmp < 0) {
4588 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004589
Daniel Veillard4c004142003-10-07 11:33:24 +00004590 prev = xmlHashLookup(ctxt->grammar->defs, name);
4591 if (prev == NULL) {
4592 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4593 "Internal error on define aggregation of %s\n",
4594 name, NULL);
4595 ret = -1;
4596 } else {
4597 while (prev->nextHash != NULL)
4598 prev = prev->nextHash;
4599 prev->nextHash = def;
4600 }
4601 }
4602 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004603 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004604 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004605}
4606
4607/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004608 * xmlRelaxNGProcessExternalRef:
4609 * @ctxt: the parser context
4610 * @node: the externlRef node
4611 *
4612 * Process and compile an externlRef node
4613 *
4614 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4615 */
4616static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004617xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4618{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004619 xmlRelaxNGDocumentPtr docu;
4620 xmlNodePtr root, tmp;
4621 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004622 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004623 xmlRelaxNGDefinePtr def;
4624
Daniel Veillard807daf82004-02-22 22:13:27 +00004625 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004626 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004627 def = xmlRelaxNGNewDefine(ctxt, node);
4628 if (def == NULL)
4629 return (NULL);
4630 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004631
Daniel Veillard4c004142003-10-07 11:33:24 +00004632 if (docu->content == NULL) {
4633 /*
4634 * Then do the parsing for good
4635 */
4636 root = xmlDocGetRootElement(docu->doc);
4637 if (root == NULL) {
4638 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4639 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4640 NULL);
4641 return (NULL);
4642 }
4643 /*
4644 * ns transmission rules
4645 */
4646 ns = xmlGetProp(root, BAD_CAST "ns");
4647 if (ns == NULL) {
4648 tmp = node;
4649 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4650 ns = xmlGetProp(tmp, BAD_CAST "ns");
4651 if (ns != NULL) {
4652 break;
4653 }
4654 tmp = tmp->parent;
4655 }
4656 if (ns != NULL) {
4657 xmlSetProp(root, BAD_CAST "ns", ns);
4658 newNs = 1;
4659 xmlFree(ns);
4660 }
4661 } else {
4662 xmlFree(ns);
4663 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004664
Daniel Veillard4c004142003-10-07 11:33:24 +00004665 /*
4666 * Parsing to get a precompiled schemas.
4667 */
4668 oldflags = ctxt->flags;
4669 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4670 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4671 ctxt->flags = oldflags;
4672 if ((docu->schema != NULL) &&
4673 (docu->schema->topgrammar != NULL)) {
4674 docu->content = docu->schema->topgrammar->start;
4675 }
4676
4677 /*
4678 * the externalRef may be reused in a different ns context
4679 */
4680 if (newNs == 1) {
4681 xmlUnsetProp(root, BAD_CAST "ns");
4682 }
4683 }
4684 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004685 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004686 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004687 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004688 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004689}
4690
4691/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004692 * xmlRelaxNGParsePattern:
4693 * @ctxt: a Relax-NG parser context
4694 * @node: the pattern node.
4695 *
4696 * parse the content of a RelaxNG pattern node.
4697 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004698 * Returns the definition pointer or NULL in case of error or if no
4699 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004700 */
4701static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004702xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4703{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004704 xmlRelaxNGDefinePtr def = NULL;
4705
Daniel Veillardd2298792003-02-14 16:54:11 +00004706 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004707 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004708 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004709 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004710 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004711 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004712 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004713 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004714 def = xmlRelaxNGNewDefine(ctxt, node);
4715 if (def == NULL)
4716 return (NULL);
4717 def->type = XML_RELAXNG_EMPTY;
4718 if (node->children != NULL) {
4719 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4720 "empty: had a child node\n", NULL, NULL);
4721 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004722 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004723 def = xmlRelaxNGNewDefine(ctxt, node);
4724 if (def == NULL)
4725 return (NULL);
4726 def->type = XML_RELAXNG_TEXT;
4727 if (node->children != NULL) {
4728 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4729 "text: had a child node\n", NULL, NULL);
4730 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004731 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004732 def = xmlRelaxNGNewDefine(ctxt, node);
4733 if (def == NULL)
4734 return (NULL);
4735 def->type = XML_RELAXNG_ZEROORMORE;
4736 if (node->children == NULL) {
4737 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4738 "Element %s is empty\n", node->name, NULL);
4739 } else {
4740 def->content =
4741 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4742 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004743 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004744 def = xmlRelaxNGNewDefine(ctxt, node);
4745 if (def == NULL)
4746 return (NULL);
4747 def->type = XML_RELAXNG_ONEORMORE;
4748 if (node->children == NULL) {
4749 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4750 "Element %s is empty\n", node->name, NULL);
4751 } else {
4752 def->content =
4753 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4754 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004755 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004756 def = xmlRelaxNGNewDefine(ctxt, node);
4757 if (def == NULL)
4758 return (NULL);
4759 def->type = XML_RELAXNG_OPTIONAL;
4760 if (node->children == NULL) {
4761 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4762 "Element %s is empty\n", node->name, NULL);
4763 } else {
4764 def->content =
4765 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4766 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004767 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004768 def = xmlRelaxNGNewDefine(ctxt, node);
4769 if (def == NULL)
4770 return (NULL);
4771 def->type = XML_RELAXNG_CHOICE;
4772 if (node->children == NULL) {
4773 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4774 "Element %s is empty\n", node->name, NULL);
4775 } else {
4776 def->content =
4777 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4778 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004779 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004780 def = xmlRelaxNGNewDefine(ctxt, node);
4781 if (def == NULL)
4782 return (NULL);
4783 def->type = XML_RELAXNG_GROUP;
4784 if (node->children == NULL) {
4785 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4786 "Element %s is empty\n", node->name, NULL);
4787 } else {
4788 def->content =
4789 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4790 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004791 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004792 def = xmlRelaxNGNewDefine(ctxt, node);
4793 if (def == NULL)
4794 return (NULL);
4795 def->type = XML_RELAXNG_REF;
4796 def->name = xmlGetProp(node, BAD_CAST "name");
4797 if (def->name == NULL) {
4798 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4799 NULL, NULL);
4800 } else {
4801 xmlRelaxNGNormExtSpace(def->name);
4802 if (xmlValidateNCName(def->name, 0)) {
4803 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4804 "ref name '%s' is not an NCName\n", def->name,
4805 NULL);
4806 }
4807 }
4808 if (node->children != NULL) {
4809 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4810 NULL, NULL);
4811 }
4812 if (ctxt->grammar->refs == NULL)
4813 ctxt->grammar->refs = xmlHashCreate(10);
4814 if (ctxt->grammar->refs == NULL) {
4815 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4816 "Could not create references hash\n", NULL, NULL);
4817 def = NULL;
4818 } else {
4819 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004820
Daniel Veillard4c004142003-10-07 11:33:24 +00004821 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4822 if (tmp < 0) {
4823 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004824
Daniel Veillard4c004142003-10-07 11:33:24 +00004825 prev = (xmlRelaxNGDefinePtr)
4826 xmlHashLookup(ctxt->grammar->refs, def->name);
4827 if (prev == NULL) {
4828 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004829 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4830 "Error refs definitions '%s'\n",
4831 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004832 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004833 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4834 "Error refs definitions\n",
4835 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004836 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004837 def = NULL;
4838 } else {
4839 def->nextHash = prev->nextHash;
4840 prev->nextHash = def;
4841 }
4842 }
4843 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004844 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004845 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004846 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004847 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004848 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004849 def = xmlRelaxNGNewDefine(ctxt, node);
4850 if (def == NULL)
4851 return (NULL);
4852 def->type = XML_RELAXNG_LIST;
4853 if (node->children == NULL) {
4854 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4855 "Element %s is empty\n", node->name, NULL);
4856 } else {
4857 def->content =
4858 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4859 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004860 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004861 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004862 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004863 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004864 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004865 def = xmlRelaxNGNewDefine(ctxt, node);
4866 if (def == NULL)
4867 return (NULL);
4868 def->type = XML_RELAXNG_NOT_ALLOWED;
4869 if (node->children != NULL) {
4870 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4871 "xmlRelaxNGParse: notAllowed element is not empty\n",
4872 NULL, NULL);
4873 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004874 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004875 xmlRelaxNGGrammarPtr grammar, old;
4876 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004877
Daniel Veillardc482e262003-02-26 14:48:48 +00004878#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004879 xmlGenericError(xmlGenericErrorContext,
4880 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004881#endif
4882
Daniel Veillard4c004142003-10-07 11:33:24 +00004883 oldparent = ctxt->parentgrammar;
4884 old = ctxt->grammar;
4885 ctxt->parentgrammar = old;
4886 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4887 if (old != NULL) {
4888 ctxt->grammar = old;
4889 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004890#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004891 if (grammar != NULL) {
4892 grammar->next = old->next;
4893 old->next = grammar;
4894 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004895#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004896 }
4897 if (grammar != NULL)
4898 def = grammar->start;
4899 else
4900 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004901 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004902 if (ctxt->parentgrammar == NULL) {
4903 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4904 "Use of parentRef without a parent grammar\n", NULL,
4905 NULL);
4906 return (NULL);
4907 }
4908 def = xmlRelaxNGNewDefine(ctxt, node);
4909 if (def == NULL)
4910 return (NULL);
4911 def->type = XML_RELAXNG_PARENTREF;
4912 def->name = xmlGetProp(node, BAD_CAST "name");
4913 if (def->name == NULL) {
4914 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4915 "parentRef has no name\n", NULL, NULL);
4916 } else {
4917 xmlRelaxNGNormExtSpace(def->name);
4918 if (xmlValidateNCName(def->name, 0)) {
4919 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4920 "parentRef name '%s' is not an NCName\n",
4921 def->name, NULL);
4922 }
4923 }
4924 if (node->children != NULL) {
4925 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4926 "parentRef is not empty\n", NULL, NULL);
4927 }
4928 if (ctxt->parentgrammar->refs == NULL)
4929 ctxt->parentgrammar->refs = xmlHashCreate(10);
4930 if (ctxt->parentgrammar->refs == NULL) {
4931 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4932 "Could not create references hash\n", NULL, NULL);
4933 def = NULL;
4934 } else if (def->name != NULL) {
4935 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004936
Daniel Veillard4c004142003-10-07 11:33:24 +00004937 tmp =
4938 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4939 if (tmp < 0) {
4940 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004941
Daniel Veillard4c004142003-10-07 11:33:24 +00004942 prev = (xmlRelaxNGDefinePtr)
4943 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4944 if (prev == NULL) {
4945 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4946 "Internal error parentRef definitions '%s'\n",
4947 def->name, NULL);
4948 def = NULL;
4949 } else {
4950 def->nextHash = prev->nextHash;
4951 prev->nextHash = def;
4952 }
4953 }
4954 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004955 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004956 if (node->children == NULL) {
4957 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4958 NULL, NULL);
4959 def = NULL;
4960 } else {
4961 def = xmlRelaxNGParseInterleave(ctxt, node);
4962 if (def != NULL) {
4963 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004964
Daniel Veillard4c004142003-10-07 11:33:24 +00004965 if ((def->content != NULL) && (def->content->next != NULL)) {
4966 tmp = xmlRelaxNGNewDefine(ctxt, node);
4967 if (tmp != NULL) {
4968 tmp->type = XML_RELAXNG_GROUP;
4969 tmp->content = def->content;
4970 def->content = tmp;
4971 }
4972 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004973
Daniel Veillard4c004142003-10-07 11:33:24 +00004974 tmp = xmlRelaxNGNewDefine(ctxt, node);
4975 if (tmp == NULL)
4976 return (def);
4977 tmp->type = XML_RELAXNG_TEXT;
4978 tmp->next = def->content;
4979 def->content = tmp;
4980 }
4981 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004982 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004983 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4984 "Unexpected node %s is not a pattern\n", node->name,
4985 NULL);
4986 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004987 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004988 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004989}
4990
4991/**
4992 * xmlRelaxNGParseAttribute:
4993 * @ctxt: a Relax-NG parser context
4994 * @node: the element node
4995 *
4996 * parse the content of a RelaxNG attribute node.
4997 *
4998 * Returns the definition pointer or NULL in case of error.
4999 */
5000static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005001xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5002{
Daniel Veillardd2298792003-02-14 16:54:11 +00005003 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005004 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005005 int old_flags;
5006
Daniel Veillardfd573f12003-03-16 17:52:32 +00005007 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005008 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005009 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005010 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005011 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005012 child = node->children;
5013 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005014 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5015 "xmlRelaxNGParseattribute: attribute has no children\n",
5016 NULL, NULL);
5017 return (ret);
5018 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005019 old_flags = ctxt->flags;
5020 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005021 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5022 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005023 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005024
Daniel Veillardd2298792003-02-14 16:54:11 +00005025 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005026 cur = xmlRelaxNGParsePattern(ctxt, child);
5027 if (cur != NULL) {
5028 switch (cur->type) {
5029 case XML_RELAXNG_EMPTY:
5030 case XML_RELAXNG_NOT_ALLOWED:
5031 case XML_RELAXNG_TEXT:
5032 case XML_RELAXNG_ELEMENT:
5033 case XML_RELAXNG_DATATYPE:
5034 case XML_RELAXNG_VALUE:
5035 case XML_RELAXNG_LIST:
5036 case XML_RELAXNG_REF:
5037 case XML_RELAXNG_PARENTREF:
5038 case XML_RELAXNG_EXTERNALREF:
5039 case XML_RELAXNG_DEF:
5040 case XML_RELAXNG_ONEORMORE:
5041 case XML_RELAXNG_ZEROORMORE:
5042 case XML_RELAXNG_OPTIONAL:
5043 case XML_RELAXNG_CHOICE:
5044 case XML_RELAXNG_GROUP:
5045 case XML_RELAXNG_INTERLEAVE:
5046 case XML_RELAXNG_ATTRIBUTE:
5047 ret->content = cur;
5048 cur->parent = ret;
5049 break;
5050 case XML_RELAXNG_START:
5051 case XML_RELAXNG_PARAM:
5052 case XML_RELAXNG_EXCEPT:
5053 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5054 "attribute has invalid content\n", NULL,
5055 NULL);
5056 break;
5057 case XML_RELAXNG_NOOP:
5058 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5059 "RNG Internal error, noop found in attribute\n",
5060 NULL, NULL);
5061 break;
5062 }
5063 }
5064 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005065 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005066 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005067 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5068 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005069 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005070 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005071 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005072}
5073
5074/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005075 * xmlRelaxNGParseExceptNameClass:
5076 * @ctxt: a Relax-NG parser context
5077 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005078 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005079 *
5080 * parse the content of a RelaxNG nameClass node.
5081 *
5082 * Returns the definition pointer or NULL in case of error.
5083 */
5084static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005085xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005086 xmlNodePtr node, int attr)
5087{
Daniel Veillard144fae12003-02-03 13:17:57 +00005088 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5089 xmlNodePtr child;
5090
Daniel Veillardd2298792003-02-14 16:54:11 +00005091 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005092 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5093 "Expecting an except node\n", NULL, NULL);
5094 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005095 }
5096 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005097 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5098 "exceptNameClass allows only a single except node\n",
5099 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005100 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005101 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005102 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5103 NULL, NULL);
5104 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005105 }
5106
Daniel Veillardfd573f12003-03-16 17:52:32 +00005107 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005108 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005109 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005110 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005111 child = node->children;
5112 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005113 cur = xmlRelaxNGNewDefine(ctxt, child);
5114 if (cur == NULL)
5115 break;
5116 if (attr)
5117 cur->type = XML_RELAXNG_ATTRIBUTE;
5118 else
5119 cur->type = XML_RELAXNG_ELEMENT;
5120
Daniel Veillard419a7682003-02-03 23:22:49 +00005121 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005122 if (last == NULL) {
5123 ret->content = cur;
5124 } else {
5125 last->next = cur;
5126 }
5127 last = cur;
5128 }
5129 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005130 }
5131
Daniel Veillard4c004142003-10-07 11:33:24 +00005132 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005133}
5134
5135/**
5136 * xmlRelaxNGParseNameClass:
5137 * @ctxt: a Relax-NG parser context
5138 * @node: the nameClass node
5139 * @def: the current definition
5140 *
5141 * parse the content of a RelaxNG nameClass node.
5142 *
5143 * Returns the definition pointer or NULL in case of error.
5144 */
5145static xmlRelaxNGDefinePtr
5146xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005147 xmlRelaxNGDefinePtr def)
5148{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005149 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005150 xmlChar *val;
5151
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005152 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005153 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005154 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005155 if ((def->type != XML_RELAXNG_ELEMENT) &&
5156 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5157 ret = xmlRelaxNGNewDefine(ctxt, node);
5158 if (ret == NULL)
5159 return (NULL);
5160 ret->parent = def;
5161 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5162 ret->type = XML_RELAXNG_ATTRIBUTE;
5163 else
5164 ret->type = XML_RELAXNG_ELEMENT;
5165 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005166 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005167 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005168 val = xmlNodeGetContent(node);
5169 xmlRelaxNGNormExtSpace(val);
5170 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005171 if (node->parent != NULL)
5172 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5173 "Element %s name '%s' is not an NCName\n",
5174 node->parent->name, val);
5175 else
5176 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5177 "name '%s' is not an NCName\n",
5178 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005179 }
5180 ret->name = val;
5181 val = xmlGetProp(node, BAD_CAST "ns");
5182 ret->ns = val;
5183 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5184 (val != NULL) &&
5185 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005186 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005187 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005188 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005189 }
5190 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5191 (val != NULL) &&
5192 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005193 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5194 "Attribute with QName 'xmlns' is not allowed\n",
5195 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005196 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005197 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005198 ret->name = NULL;
5199 ret->ns = NULL;
5200 if (node->children != NULL) {
5201 ret->nameClass =
5202 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5203 (def->type ==
5204 XML_RELAXNG_ATTRIBUTE));
5205 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005206 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005207 ret->name = NULL;
5208 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5209 if (ret->ns == NULL) {
5210 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5211 "nsName has no ns attribute\n", NULL, NULL);
5212 }
5213 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5214 (ret->ns != NULL) &&
5215 (xmlStrEqual
5216 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5217 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5218 "Attribute with namespace '%s' is not allowed\n",
5219 ret->ns, NULL);
5220 }
5221 if (node->children != NULL) {
5222 ret->nameClass =
5223 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5224 (def->type ==
5225 XML_RELAXNG_ATTRIBUTE));
5226 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005227 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005228 xmlNodePtr child;
5229 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005230
Daniel Veillard4c004142003-10-07 11:33:24 +00005231 ret = xmlRelaxNGNewDefine(ctxt, node);
5232 if (ret == NULL)
5233 return (NULL);
5234 ret->parent = def;
5235 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005236
Daniel Veillard4c004142003-10-07 11:33:24 +00005237 if (node->children == NULL) {
5238 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5239 "Element choice is empty\n", NULL, NULL);
5240 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005241
Daniel Veillard4c004142003-10-07 11:33:24 +00005242 child = node->children;
5243 while (child != NULL) {
5244 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5245 if (tmp != NULL) {
5246 if (last == NULL) {
5247 last = ret->nameClass = tmp;
5248 } else {
5249 last->next = tmp;
5250 last = tmp;
5251 }
5252 }
5253 child = child->next;
5254 }
5255 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005256 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005257 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5258 "expecting name, anyName, nsName or choice : got %s\n",
5259 node->name, NULL);
5260 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005261 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005262 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005263 if (def->nameClass == NULL) {
5264 def->nameClass = ret;
5265 } else {
5266 tmp = def->nameClass;
5267 while (tmp->next != NULL) {
5268 tmp = tmp->next;
5269 }
5270 tmp->next = ret;
5271 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005272 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005273 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005274}
5275
5276/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005277 * xmlRelaxNGParseElement:
5278 * @ctxt: a Relax-NG parser context
5279 * @node: the element node
5280 *
5281 * parse the content of a RelaxNG element node.
5282 *
5283 * Returns the definition pointer or NULL in case of error.
5284 */
5285static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005286xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5287{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005288 xmlRelaxNGDefinePtr ret, cur, last;
5289 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005290 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005291
Daniel Veillardfd573f12003-03-16 17:52:32 +00005292 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005293 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005294 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005295 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005296 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005297 child = node->children;
5298 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005299 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5300 "xmlRelaxNGParseElement: element has no children\n",
5301 NULL, NULL);
5302 return (ret);
5303 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005304 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5305 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005306 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005307
Daniel Veillard6eadf632003-01-23 18:29:16 +00005308 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005309 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5310 "xmlRelaxNGParseElement: element has no content\n",
5311 NULL, NULL);
5312 return (ret);
5313 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005314 olddefine = ctxt->define;
5315 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005316 last = NULL;
5317 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005318 cur = xmlRelaxNGParsePattern(ctxt, child);
5319 if (cur != NULL) {
5320 cur->parent = ret;
5321 switch (cur->type) {
5322 case XML_RELAXNG_EMPTY:
5323 case XML_RELAXNG_NOT_ALLOWED:
5324 case XML_RELAXNG_TEXT:
5325 case XML_RELAXNG_ELEMENT:
5326 case XML_RELAXNG_DATATYPE:
5327 case XML_RELAXNG_VALUE:
5328 case XML_RELAXNG_LIST:
5329 case XML_RELAXNG_REF:
5330 case XML_RELAXNG_PARENTREF:
5331 case XML_RELAXNG_EXTERNALREF:
5332 case XML_RELAXNG_DEF:
5333 case XML_RELAXNG_ZEROORMORE:
5334 case XML_RELAXNG_ONEORMORE:
5335 case XML_RELAXNG_OPTIONAL:
5336 case XML_RELAXNG_CHOICE:
5337 case XML_RELAXNG_GROUP:
5338 case XML_RELAXNG_INTERLEAVE:
5339 if (last == NULL) {
5340 ret->content = last = cur;
5341 } else {
5342 if ((last->type == XML_RELAXNG_ELEMENT) &&
5343 (ret->content == last)) {
5344 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5345 if (ret->content != NULL) {
5346 ret->content->type = XML_RELAXNG_GROUP;
5347 ret->content->content = last;
5348 } else {
5349 ret->content = last;
5350 }
5351 }
5352 last->next = cur;
5353 last = cur;
5354 }
5355 break;
5356 case XML_RELAXNG_ATTRIBUTE:
5357 cur->next = ret->attrs;
5358 ret->attrs = cur;
5359 break;
5360 case XML_RELAXNG_START:
5361 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5362 "RNG Internal error, start found in element\n",
5363 NULL, NULL);
5364 break;
5365 case XML_RELAXNG_PARAM:
5366 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5367 "RNG Internal error, param found in element\n",
5368 NULL, NULL);
5369 break;
5370 case XML_RELAXNG_EXCEPT:
5371 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5372 "RNG Internal error, except found in element\n",
5373 NULL, NULL);
5374 break;
5375 case XML_RELAXNG_NOOP:
5376 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5377 "RNG Internal error, noop found in element\n",
5378 NULL, NULL);
5379 break;
5380 }
5381 }
5382 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005383 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005384 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005385 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005386}
5387
5388/**
5389 * xmlRelaxNGParsePatterns:
5390 * @ctxt: a Relax-NG parser context
5391 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005392 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005393 *
5394 * parse the content of a RelaxNG start node.
5395 *
5396 * Returns the definition pointer or NULL in case of error.
5397 */
5398static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005399xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005400 int group)
5401{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005402 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005403
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005404 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005405 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005406 if (IS_RELAXNG(nodes, "element")) {
5407 cur = xmlRelaxNGParseElement(ctxt, nodes);
5408 if (def == NULL) {
5409 def = last = cur;
5410 } else {
5411 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5412 (def == last)) {
5413 def = xmlRelaxNGNewDefine(ctxt, nodes);
5414 def->type = XML_RELAXNG_GROUP;
5415 def->content = last;
5416 }
5417 last->next = cur;
5418 last = cur;
5419 }
5420 cur->parent = parent;
5421 } else {
5422 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5423 if (cur != NULL) {
5424 if (def == NULL) {
5425 def = last = cur;
5426 } else {
5427 last->next = cur;
5428 last = cur;
5429 }
5430 }
5431 }
5432 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005433 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005434 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005435}
5436
5437/**
5438 * xmlRelaxNGParseStart:
5439 * @ctxt: a Relax-NG parser context
5440 * @nodes: start children nodes
5441 *
5442 * parse the content of a RelaxNG start node.
5443 *
5444 * Returns 0 in case of success, -1 in case of error
5445 */
5446static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005447xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5448{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005449 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005450 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005451
Daniel Veillardd2298792003-02-14 16:54:11 +00005452 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005453 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5454 NULL, NULL);
5455 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005456 }
5457 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005458 def = xmlRelaxNGNewDefine(ctxt, nodes);
5459 if (def == NULL)
5460 return (-1);
5461 def->type = XML_RELAXNG_EMPTY;
5462 if (nodes->children != NULL) {
5463 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5464 "element empty is not empty\n", NULL, NULL);
5465 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005466 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005467 def = xmlRelaxNGNewDefine(ctxt, nodes);
5468 if (def == NULL)
5469 return (-1);
5470 def->type = XML_RELAXNG_NOT_ALLOWED;
5471 if (nodes->children != NULL) {
5472 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5473 "element notAllowed is not empty\n", NULL, NULL);
5474 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005475 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005476 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005477 }
5478 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005479 last = ctxt->grammar->start;
5480 while (last->next != NULL)
5481 last = last->next;
5482 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005483 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005484 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005485 }
5486 nodes = nodes->next;
5487 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005488 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5489 "start more than one children\n", NULL, NULL);
5490 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005491 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005492 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005493}
5494
5495/**
5496 * xmlRelaxNGParseGrammarContent:
5497 * @ctxt: a Relax-NG parser context
5498 * @nodes: grammar children nodes
5499 *
5500 * parse the content of a RelaxNG grammar node.
5501 *
5502 * Returns 0 in case of success, -1 in case of error
5503 */
5504static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005505xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5506 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005507{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005508 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005509
5510 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005511 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5512 "grammar has no children\n", NULL, NULL);
5513 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005514 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005515 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005516 if (IS_RELAXNG(nodes, "start")) {
5517 if (nodes->children == NULL) {
5518 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5519 "start has no children\n", NULL, NULL);
5520 } else {
5521 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5522 if (tmp != 0)
5523 ret = -1;
5524 }
5525 } else if (IS_RELAXNG(nodes, "define")) {
5526 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5527 if (tmp != 0)
5528 ret = -1;
5529 } else if (IS_RELAXNG(nodes, "include")) {
5530 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5531 if (tmp != 0)
5532 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005533 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005534 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5535 "grammar has unexpected child %s\n", nodes->name,
5536 NULL);
5537 ret = -1;
5538 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005539 nodes = nodes->next;
5540 }
5541 return (ret);
5542}
5543
5544/**
5545 * xmlRelaxNGCheckReference:
5546 * @ref: the ref
5547 * @ctxt: a Relax-NG parser context
5548 * @name: the name associated to the defines
5549 *
5550 * Applies the 4.17. combine attribute rule for all the define
5551 * element of a given grammar using the same name.
5552 */
5553static void
5554xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005555 xmlRelaxNGParserCtxtPtr ctxt,
5556 const xmlChar * name)
5557{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005558 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005559 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005560
5561 grammar = ctxt->grammar;
5562 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005563 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5564 "Internal error: no grammar in CheckReference %s\n",
5565 name, NULL);
5566 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005567 }
5568 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005569 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5570 "Internal error: reference has content in CheckReference %s\n",
5571 name, NULL);
5572 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005573 }
5574 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005575 def = xmlHashLookup(grammar->defs, name);
5576 if (def != NULL) {
5577 cur = ref;
5578 while (cur != NULL) {
5579 cur->content = def;
5580 cur = cur->nextHash;
5581 }
5582 } else {
5583 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5584 "Reference %s has no matching definition\n", name,
5585 NULL);
5586 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005587 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005588 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5589 "Reference %s has no matching definition\n", name,
5590 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005591 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005592}
5593
5594/**
5595 * xmlRelaxNGCheckCombine:
5596 * @define: the define(s) list
5597 * @ctxt: a Relax-NG parser context
5598 * @name: the name associated to the defines
5599 *
5600 * Applies the 4.17. combine attribute rule for all the define
5601 * element of a given grammar using the same name.
5602 */
5603static void
5604xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005605 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5606{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005607 xmlChar *combine;
5608 int choiceOrInterleave = -1;
5609 int missing = 0;
5610 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5611
5612 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005613 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005614 cur = define;
5615 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005616 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5617 if (combine != NULL) {
5618 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5619 if (choiceOrInterleave == -1)
5620 choiceOrInterleave = 1;
5621 else if (choiceOrInterleave == 0) {
5622 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5623 "Defines for %s use both 'choice' and 'interleave'\n",
5624 name, NULL);
5625 }
5626 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5627 if (choiceOrInterleave == -1)
5628 choiceOrInterleave = 0;
5629 else if (choiceOrInterleave == 1) {
5630 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5631 "Defines for %s use both 'choice' and 'interleave'\n",
5632 name, NULL);
5633 }
5634 } else {
5635 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5636 "Defines for %s use unknown combine value '%s''\n",
5637 name, combine);
5638 }
5639 xmlFree(combine);
5640 } else {
5641 if (missing == 0)
5642 missing = 1;
5643 else {
5644 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5645 "Some defines for %s needs the combine attribute\n",
5646 name, NULL);
5647 }
5648 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005649
Daniel Veillard4c004142003-10-07 11:33:24 +00005650 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005651 }
5652#ifdef DEBUG
5653 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005654 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5655 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005656#endif
5657 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005658 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005659 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005660 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005661 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005662 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005663 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005664 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005665 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005666 tmp = define;
5667 last = NULL;
5668 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005669 if (tmp->content != NULL) {
5670 if (tmp->content->next != NULL) {
5671 /*
5672 * we need first to create a wrapper.
5673 */
5674 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5675 if (tmp2 == NULL)
5676 break;
5677 tmp2->type = XML_RELAXNG_GROUP;
5678 tmp2->content = tmp->content;
5679 } else {
5680 tmp2 = tmp->content;
5681 }
5682 if (last == NULL) {
5683 cur->content = tmp2;
5684 } else {
5685 last->next = tmp2;
5686 }
5687 last = tmp2;
5688 }
5689 tmp->content = cur;
5690 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005691 }
5692 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005693 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005694 if (ctxt->interleaves == NULL)
5695 ctxt->interleaves = xmlHashCreate(10);
5696 if (ctxt->interleaves == NULL) {
5697 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5698 "Failed to create interleaves hash table\n", NULL,
5699 NULL);
5700 } else {
5701 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005702
Daniel Veillard4c004142003-10-07 11:33:24 +00005703 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5704 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5705 0) {
5706 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5707 "Failed to add %s to hash table\n",
5708 (const xmlChar *) tmpname, NULL);
5709 }
5710 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005711 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005712}
5713
5714/**
5715 * xmlRelaxNGCombineStart:
5716 * @ctxt: a Relax-NG parser context
5717 * @grammar: the grammar
5718 *
5719 * Applies the 4.17. combine rule for all the start
5720 * element of a given grammar.
5721 */
5722static void
5723xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005724 xmlRelaxNGGrammarPtr grammar)
5725{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005726 xmlRelaxNGDefinePtr starts;
5727 xmlChar *combine;
5728 int choiceOrInterleave = -1;
5729 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005730 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005731
Daniel Veillard2df2de22003-02-17 23:34:33 +00005732 starts = grammar->start;
5733 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005734 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005735 cur = starts;
5736 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005737 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5738 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5739 combine = NULL;
5740 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5741 "Internal error: start element not found\n", NULL,
5742 NULL);
5743 } else {
5744 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5745 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005746
Daniel Veillard4c004142003-10-07 11:33:24 +00005747 if (combine != NULL) {
5748 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5749 if (choiceOrInterleave == -1)
5750 choiceOrInterleave = 1;
5751 else if (choiceOrInterleave == 0) {
5752 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5753 "<start> use both 'choice' and 'interleave'\n",
5754 NULL, NULL);
5755 }
5756 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5757 if (choiceOrInterleave == -1)
5758 choiceOrInterleave = 0;
5759 else if (choiceOrInterleave == 1) {
5760 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5761 "<start> use both 'choice' and 'interleave'\n",
5762 NULL, NULL);
5763 }
5764 } else {
5765 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5766 "<start> uses unknown combine value '%s''\n",
5767 combine, NULL);
5768 }
5769 xmlFree(combine);
5770 } else {
5771 if (missing == 0)
5772 missing = 1;
5773 else {
5774 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5775 "Some <start> element miss the combine attribute\n",
5776 NULL, NULL);
5777 }
5778 }
5779
5780 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005781 }
5782#ifdef DEBUG
5783 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005784 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5785 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005786#endif
5787 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005788 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005789 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005790 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005791 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005792 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005793 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005794 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005795 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005796 cur->content = grammar->start;
5797 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005798 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005799 if (ctxt->interleaves == NULL)
5800 ctxt->interleaves = xmlHashCreate(10);
5801 if (ctxt->interleaves == NULL) {
5802 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5803 "Failed to create interleaves hash table\n", NULL,
5804 NULL);
5805 } else {
5806 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005807
Daniel Veillard4c004142003-10-07 11:33:24 +00005808 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5809 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5810 0) {
5811 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5812 "Failed to add %s to hash table\n",
5813 (const xmlChar *) tmpname, NULL);
5814 }
5815 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005816 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005817}
5818
5819/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005820 * xmlRelaxNGCheckCycles:
5821 * @ctxt: a Relax-NG parser context
5822 * @nodes: grammar children nodes
5823 * @depth: the counter
5824 *
5825 * Check for cycles.
5826 *
5827 * Returns 0 if check passed, and -1 in case of error
5828 */
5829static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005830xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5831 xmlRelaxNGDefinePtr cur, int depth)
5832{
Daniel Veillardd4310742003-02-18 21:12:46 +00005833 int ret = 0;
5834
5835 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005836 if ((cur->type == XML_RELAXNG_REF) ||
5837 (cur->type == XML_RELAXNG_PARENTREF)) {
5838 if (cur->depth == -1) {
5839 cur->depth = depth;
5840 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5841 cur->depth = -2;
5842 } else if (depth == cur->depth) {
5843 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5844 "Detected a cycle in %s references\n",
5845 cur->name, NULL);
5846 return (-1);
5847 }
5848 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5849 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5850 } else {
5851 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5852 }
5853 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005854 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005855 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005856}
5857
5858/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005859 * xmlRelaxNGTryUnlink:
5860 * @ctxt: a Relax-NG parser context
5861 * @cur: the definition to unlink
5862 * @parent: the parent definition
5863 * @prev: the previous sibling definition
5864 *
5865 * Try to unlink a definition. If not possble make it a NOOP
5866 *
5867 * Returns the new prev definition
5868 */
5869static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005870xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5871 xmlRelaxNGDefinePtr cur,
5872 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5873{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005874 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005875 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005876 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005877 if (parent != NULL) {
5878 if (parent->content == cur)
5879 parent->content = cur->next;
5880 else if (parent->attrs == cur)
5881 parent->attrs = cur->next;
5882 else if (parent->nameClass == cur)
5883 parent->nameClass = cur->next;
5884 } else {
5885 cur->type = XML_RELAXNG_NOOP;
5886 prev = cur;
5887 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005888 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005889 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005890}
5891
5892/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005893 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005894 * @ctxt: a Relax-NG parser context
5895 * @nodes: grammar children nodes
5896 *
5897 * Check for simplification of empty and notAllowed
5898 */
5899static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005900xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5901 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5902{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005903 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005904
Daniel Veillardfd573f12003-03-16 17:52:32 +00005905 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005906 if ((cur->type == XML_RELAXNG_REF) ||
5907 (cur->type == XML_RELAXNG_PARENTREF)) {
5908 if (cur->depth != -3) {
5909 cur->depth = -3;
5910 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5911 }
5912 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5913 cur->parent = parent;
5914 if ((parent != NULL) &&
5915 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5916 (parent->type == XML_RELAXNG_LIST) ||
5917 (parent->type == XML_RELAXNG_GROUP) ||
5918 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5919 (parent->type == XML_RELAXNG_ONEORMORE) ||
5920 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5921 parent->type = XML_RELAXNG_NOT_ALLOWED;
5922 break;
5923 }
5924 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5925 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5926 } else
5927 prev = cur;
5928 } else if (cur->type == XML_RELAXNG_EMPTY) {
5929 cur->parent = parent;
5930 if ((parent != NULL) &&
5931 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5932 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5933 parent->type = XML_RELAXNG_EMPTY;
5934 break;
5935 }
5936 if ((parent != NULL) &&
5937 ((parent->type == XML_RELAXNG_GROUP) ||
5938 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5939 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5940 } else
5941 prev = cur;
5942 } else {
5943 cur->parent = parent;
5944 if (cur->content != NULL)
5945 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5946 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5947 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5948 if (cur->nameClass != NULL)
5949 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5950 /*
5951 * On Elements, try to move attribute only generating rules on
5952 * the attrs rules.
5953 */
5954 if (cur->type == XML_RELAXNG_ELEMENT) {
5955 int attronly;
5956 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005957
Daniel Veillard4c004142003-10-07 11:33:24 +00005958 while (cur->content != NULL) {
5959 attronly =
5960 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5961 if (attronly == 1) {
5962 /*
5963 * migrate cur->content to attrs
5964 */
5965 tmp = cur->content;
5966 cur->content = tmp->next;
5967 tmp->next = cur->attrs;
5968 cur->attrs = tmp;
5969 } else {
5970 /*
5971 * cur->content can generate elements or text
5972 */
5973 break;
5974 }
5975 }
5976 pre = cur->content;
5977 while ((pre != NULL) && (pre->next != NULL)) {
5978 tmp = pre->next;
5979 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5980 if (attronly == 1) {
5981 /*
5982 * migrate tmp to attrs
5983 */
5984 pre->next = tmp->next;
5985 tmp->next = cur->attrs;
5986 cur->attrs = tmp;
5987 } else {
5988 pre = tmp;
5989 }
5990 }
5991 }
5992 /*
5993 * This may result in a simplification
5994 */
5995 if ((cur->type == XML_RELAXNG_GROUP) ||
5996 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5997 if (cur->content == NULL)
5998 cur->type = XML_RELAXNG_EMPTY;
5999 else if (cur->content->next == NULL) {
6000 if ((parent == NULL) && (prev == NULL)) {
6001 cur->type = XML_RELAXNG_NOOP;
6002 } else if (prev == NULL) {
6003 parent->content = cur->content;
6004 cur->content->next = cur->next;
6005 cur = cur->content;
6006 } else {
6007 cur->content->next = cur->next;
6008 prev->next = cur->content;
6009 cur = cur->content;
6010 }
6011 }
6012 }
6013 /*
6014 * the current node may have been transformed back
6015 */
6016 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6017 (cur->content != NULL) &&
6018 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6019 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6020 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6021 if ((parent != NULL) &&
6022 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6023 (parent->type == XML_RELAXNG_LIST) ||
6024 (parent->type == XML_RELAXNG_GROUP) ||
6025 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6026 (parent->type == XML_RELAXNG_ONEORMORE) ||
6027 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6028 parent->type = XML_RELAXNG_NOT_ALLOWED;
6029 break;
6030 }
6031 if ((parent != NULL) &&
6032 (parent->type == XML_RELAXNG_CHOICE)) {
6033 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6034 } else
6035 prev = cur;
6036 } else if (cur->type == XML_RELAXNG_EMPTY) {
6037 if ((parent != NULL) &&
6038 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6039 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6040 parent->type = XML_RELAXNG_EMPTY;
6041 break;
6042 }
6043 if ((parent != NULL) &&
6044 ((parent->type == XML_RELAXNG_GROUP) ||
6045 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6046 (parent->type == XML_RELAXNG_CHOICE))) {
6047 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6048 } else
6049 prev = cur;
6050 } else {
6051 prev = cur;
6052 }
6053 }
6054 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006055 }
6056}
6057
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006058/**
6059 * xmlRelaxNGGroupContentType:
6060 * @ct1: the first content type
6061 * @ct2: the second content type
6062 *
6063 * Try to group 2 content types
6064 *
6065 * Returns the content type
6066 */
6067static xmlRelaxNGContentType
6068xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006069 xmlRelaxNGContentType ct2)
6070{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006071 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006072 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6073 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006074 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006075 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006076 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006077 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006078 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006079 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6080 return (XML_RELAXNG_CONTENT_COMPLEX);
6081 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006082}
6083
6084/**
6085 * xmlRelaxNGMaxContentType:
6086 * @ct1: the first content type
6087 * @ct2: the second content type
6088 *
6089 * Compute the max content-type
6090 *
6091 * Returns the content type
6092 */
6093static xmlRelaxNGContentType
6094xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006095 xmlRelaxNGContentType ct2)
6096{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006097 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006098 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6099 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006100 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006101 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6102 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006103 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006104 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6105 return (XML_RELAXNG_CONTENT_COMPLEX);
6106 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006107}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006108
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006109/**
6110 * xmlRelaxNGCheckRules:
6111 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006112 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006113 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006114 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006115 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006116 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006117 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006118 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006119 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006120static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006121xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6122 xmlRelaxNGDefinePtr cur, int flags,
6123 xmlRelaxNGType ptype)
6124{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006125 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006126 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006127
Daniel Veillardfd573f12003-03-16 17:52:32 +00006128 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006129 ret = XML_RELAXNG_CONTENT_EMPTY;
6130 if ((cur->type == XML_RELAXNG_REF) ||
6131 (cur->type == XML_RELAXNG_PARENTREF)) {
Daniel Veillard63d68a32005-03-31 13:50:00 +00006132 /*
6133 * This should actually be caught by list//element(ref) at the
6134 * element boundaries, c.f. Bug #159968 local refs are dropped
6135 * in step 4.19.
6136 */
6137#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00006138 if (flags & XML_RELAXNG_IN_LIST) {
6139 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6140 "Found forbidden pattern list//ref\n", NULL,
6141 NULL);
6142 }
Daniel Veillard63d68a32005-03-31 13:50:00 +00006143#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00006144 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6145 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6146 "Found forbidden pattern data/except//ref\n",
6147 NULL, NULL);
6148 }
6149 if (cur->depth > -4) {
6150 cur->depth = -4;
6151 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6152 flags, cur->type);
6153 cur->depth = ret - 15;
6154 } else if (cur->depth == -4) {
6155 ret = XML_RELAXNG_CONTENT_COMPLEX;
6156 } else {
6157 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6158 }
6159 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6160 /*
6161 * The 7.3 Attribute derivation rule for groups is plugged there
6162 */
6163 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6164 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6165 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6166 "Found forbidden pattern data/except//element(ref)\n",
6167 NULL, NULL);
6168 }
6169 if (flags & XML_RELAXNG_IN_LIST) {
6170 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6171 "Found forbidden pattern list//element(ref)\n",
6172 NULL, NULL);
6173 }
6174 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6175 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6176 "Found forbidden pattern attribute//element(ref)\n",
6177 NULL, NULL);
6178 }
6179 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6180 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6181 "Found forbidden pattern attribute//element(ref)\n",
6182 NULL, NULL);
6183 }
6184 /*
6185 * reset since in the simple form elements are only child
6186 * of grammar/define
6187 */
6188 nflags = 0;
6189 ret =
6190 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6191 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6192 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6193 "Element %s attributes have a content type error\n",
6194 cur->name, NULL);
6195 }
6196 ret =
6197 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6198 cur->type);
6199 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6200 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6201 "Element %s has a content type error\n",
6202 cur->name, NULL);
6203 } else {
6204 ret = XML_RELAXNG_CONTENT_COMPLEX;
6205 }
6206 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6207 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6208 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6209 "Found forbidden pattern attribute//attribute\n",
6210 NULL, NULL);
6211 }
6212 if (flags & XML_RELAXNG_IN_LIST) {
6213 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6214 "Found forbidden pattern list//attribute\n",
6215 NULL, NULL);
6216 }
6217 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6218 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6219 "Found forbidden pattern oneOrMore//group//attribute\n",
6220 NULL, NULL);
6221 }
6222 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6223 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6224 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6225 NULL, NULL);
6226 }
6227 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6228 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6229 "Found forbidden pattern data/except//attribute\n",
6230 NULL, NULL);
6231 }
6232 if (flags & XML_RELAXNG_IN_START) {
6233 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6234 "Found forbidden pattern start//attribute\n",
6235 NULL, NULL);
6236 }
6237 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6238 && (cur->name == NULL)) {
6239 if (cur->ns == NULL) {
6240 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6241 "Found anyName attribute without oneOrMore ancestor\n",
6242 NULL, NULL);
6243 } else {
6244 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6245 "Found nsName attribute without oneOrMore ancestor\n",
6246 NULL, NULL);
6247 }
6248 }
6249 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6250 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6251 ret = XML_RELAXNG_CONTENT_EMPTY;
6252 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6253 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6254 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6255 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6256 "Found forbidden pattern data/except//oneOrMore\n",
6257 NULL, NULL);
6258 }
6259 if (flags & XML_RELAXNG_IN_START) {
6260 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6261 "Found forbidden pattern start//oneOrMore\n",
6262 NULL, NULL);
6263 }
6264 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6265 ret =
6266 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6267 cur->type);
6268 ret = xmlRelaxNGGroupContentType(ret, ret);
6269 } else if (cur->type == XML_RELAXNG_LIST) {
6270 if (flags & XML_RELAXNG_IN_LIST) {
6271 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6272 "Found forbidden pattern list//list\n", NULL,
6273 NULL);
6274 }
6275 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6276 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6277 "Found forbidden pattern data/except//list\n",
6278 NULL, NULL);
6279 }
6280 if (flags & XML_RELAXNG_IN_START) {
6281 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6282 "Found forbidden pattern start//list\n", NULL,
6283 NULL);
6284 }
6285 nflags = flags | XML_RELAXNG_IN_LIST;
6286 ret =
6287 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6288 cur->type);
6289 } else if (cur->type == XML_RELAXNG_GROUP) {
6290 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6291 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6292 "Found forbidden pattern data/except//group\n",
6293 NULL, NULL);
6294 }
6295 if (flags & XML_RELAXNG_IN_START) {
6296 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6297 "Found forbidden pattern start//group\n", NULL,
6298 NULL);
6299 }
6300 if (flags & XML_RELAXNG_IN_ONEORMORE)
6301 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6302 else
6303 nflags = flags;
6304 ret =
6305 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6306 cur->type);
6307 /*
6308 * The 7.3 Attribute derivation rule for groups is plugged there
6309 */
6310 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6311 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6312 if (flags & XML_RELAXNG_IN_LIST) {
6313 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6314 "Found forbidden pattern list//interleave\n",
6315 NULL, NULL);
6316 }
6317 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6318 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6319 "Found forbidden pattern data/except//interleave\n",
6320 NULL, NULL);
6321 }
6322 if (flags & XML_RELAXNG_IN_START) {
6323 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6324 "Found forbidden pattern start//interleave\n",
6325 NULL, NULL);
6326 }
6327 if (flags & XML_RELAXNG_IN_ONEORMORE)
6328 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6329 else
6330 nflags = flags;
6331 ret =
6332 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6333 cur->type);
6334 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6335 if ((cur->parent != NULL) &&
6336 (cur->parent->type == XML_RELAXNG_DATATYPE))
6337 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6338 else
6339 nflags = flags;
6340 ret =
6341 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6342 cur->type);
6343 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6344 if (flags & XML_RELAXNG_IN_START) {
6345 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6346 "Found forbidden pattern start//data\n", NULL,
6347 NULL);
6348 }
6349 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6350 ret = XML_RELAXNG_CONTENT_SIMPLE;
6351 } else if (cur->type == XML_RELAXNG_VALUE) {
6352 if (flags & XML_RELAXNG_IN_START) {
6353 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6354 "Found forbidden pattern start//value\n", NULL,
6355 NULL);
6356 }
6357 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6358 ret = XML_RELAXNG_CONTENT_SIMPLE;
6359 } else if (cur->type == XML_RELAXNG_TEXT) {
6360 if (flags & XML_RELAXNG_IN_LIST) {
6361 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6362 "Found forbidden pattern list//text\n", NULL,
6363 NULL);
6364 }
6365 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6366 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6367 "Found forbidden pattern data/except//text\n",
6368 NULL, NULL);
6369 }
6370 if (flags & XML_RELAXNG_IN_START) {
6371 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6372 "Found forbidden pattern start//text\n", NULL,
6373 NULL);
6374 }
6375 ret = XML_RELAXNG_CONTENT_COMPLEX;
6376 } else if (cur->type == XML_RELAXNG_EMPTY) {
6377 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6378 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6379 "Found forbidden pattern data/except//empty\n",
6380 NULL, NULL);
6381 }
6382 if (flags & XML_RELAXNG_IN_START) {
6383 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6384 "Found forbidden pattern start//empty\n", NULL,
6385 NULL);
6386 }
6387 ret = XML_RELAXNG_CONTENT_EMPTY;
6388 } else if (cur->type == XML_RELAXNG_CHOICE) {
6389 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6390 ret =
6391 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6392 } else {
6393 ret =
6394 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6395 }
6396 cur = cur->next;
6397 if (ptype == XML_RELAXNG_GROUP) {
6398 val = xmlRelaxNGGroupContentType(val, ret);
6399 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6400 tmp = xmlRelaxNGGroupContentType(val, ret);
6401 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6402 tmp = xmlRelaxNGMaxContentType(val, ret);
6403 } else if (ptype == XML_RELAXNG_CHOICE) {
6404 val = xmlRelaxNGMaxContentType(val, ret);
6405 } else if (ptype == XML_RELAXNG_LIST) {
6406 val = XML_RELAXNG_CONTENT_SIMPLE;
6407 } else if (ptype == XML_RELAXNG_EXCEPT) {
6408 if (ret == XML_RELAXNG_CONTENT_ERROR)
6409 val = XML_RELAXNG_CONTENT_ERROR;
6410 else
6411 val = XML_RELAXNG_CONTENT_SIMPLE;
6412 } else {
6413 val = xmlRelaxNGGroupContentType(val, ret);
6414 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006415
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006416 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006417 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006418}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006419
6420/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006421 * xmlRelaxNGParseGrammar:
6422 * @ctxt: a Relax-NG parser context
6423 * @nodes: grammar children nodes
6424 *
6425 * parse a Relax-NG <grammar> node
6426 *
6427 * Returns the internal xmlRelaxNGGrammarPtr built or
6428 * NULL in case of error
6429 */
6430static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006431xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6432{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006433 xmlRelaxNGGrammarPtr ret, tmp, old;
6434
Daniel Veillardc482e262003-02-26 14:48:48 +00006435#ifdef DEBUG_GRAMMAR
6436 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6437#endif
6438
Daniel Veillard6eadf632003-01-23 18:29:16 +00006439 ret = xmlRelaxNGNewGrammar(ctxt);
6440 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006441 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006442
6443 /*
6444 * Link the new grammar in the tree
6445 */
6446 ret->parent = ctxt->grammar;
6447 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006448 tmp = ctxt->grammar->children;
6449 if (tmp == NULL) {
6450 ctxt->grammar->children = ret;
6451 } else {
6452 while (tmp->next != NULL)
6453 tmp = tmp->next;
6454 tmp->next = ret;
6455 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006456 }
6457
6458 old = ctxt->grammar;
6459 ctxt->grammar = ret;
6460 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6461 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006462 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006463 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6464 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006465 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006466 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6467 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006468 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469
6470 /*
6471 * Apply 4.17 mergingd rules to defines and starts
6472 */
6473 xmlRelaxNGCombineStart(ctxt, ret);
6474 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006475 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6476 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006477 }
6478
6479 /*
6480 * link together defines and refs in this grammar
6481 */
6482 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006483 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6484 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006485 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006486
Daniel Veillard6eadf632003-01-23 18:29:16 +00006487 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006488 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006489}
6490
6491/**
6492 * xmlRelaxNGParseDocument:
6493 * @ctxt: a Relax-NG parser context
6494 * @node: the root node of the RelaxNG schema
6495 *
6496 * parse a Relax-NG definition resource and build an internal
6497 * xmlRelaxNG struture which can be used to validate instances.
6498 *
6499 * Returns the internal XML RelaxNG structure built or
6500 * NULL in case of error
6501 */
6502static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006503xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6504{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006505 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006506 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006507 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006508
6509 if ((ctxt == NULL) || (node == NULL))
6510 return (NULL);
6511
6512 schema = xmlRelaxNGNewRelaxNG(ctxt);
6513 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006514 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006515
Daniel Veillard276be4a2003-01-24 01:03:34 +00006516 olddefine = ctxt->define;
6517 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006518 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006519 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006520 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006521 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006522
Daniel Veillard4c004142003-10-07 11:33:24 +00006523 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6524 if (schema->topgrammar == NULL) {
6525 return (schema);
6526 }
6527 /*
6528 * Link the new grammar in the tree
6529 */
6530 ret->parent = ctxt->grammar;
6531 if (ctxt->grammar != NULL) {
6532 tmp = ctxt->grammar->children;
6533 if (tmp == NULL) {
6534 ctxt->grammar->children = ret;
6535 } else {
6536 while (tmp->next != NULL)
6537 tmp = tmp->next;
6538 tmp->next = ret;
6539 }
6540 }
6541 old = ctxt->grammar;
6542 ctxt->grammar = ret;
6543 xmlRelaxNGParseStart(ctxt, node);
6544 if (old != NULL)
6545 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006546 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006547 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006548 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006549 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6550 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6551 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6552 while ((schema->topgrammar->start != NULL) &&
6553 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6554 (schema->topgrammar->start->next != NULL))
6555 schema->topgrammar->start =
6556 schema->topgrammar->start->content;
6557 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6558 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6559 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006560 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006561#ifdef DEBUG
6562 if (schema == NULL)
6563 xmlGenericError(xmlGenericErrorContext,
6564 "xmlRelaxNGParseDocument() failed\n");
6565#endif
6566
6567 return (schema);
6568}
6569
6570/************************************************************************
6571 * *
6572 * Reading RelaxNGs *
6573 * *
6574 ************************************************************************/
6575
6576/**
6577 * xmlRelaxNGNewParserCtxt:
6578 * @URL: the location of the schema
6579 *
6580 * Create an XML RelaxNGs parse context for that file/resource expected
6581 * to contain an XML RelaxNGs file.
6582 *
6583 * Returns the parser context or NULL in case of error
6584 */
6585xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006586xmlRelaxNGNewParserCtxt(const char *URL)
6587{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006588 xmlRelaxNGParserCtxtPtr ret;
6589
6590 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006591 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006592
Daniel Veillard4c004142003-10-07 11:33:24 +00006593 ret =
6594 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006595 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006596 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006597 return (NULL);
6598 }
6599 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006600 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006601 ret->error = xmlGenericError;
6602 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006603 return (ret);
6604}
6605
6606/**
6607 * xmlRelaxNGNewMemParserCtxt:
6608 * @buffer: a pointer to a char array containing the schemas
6609 * @size: the size of the array
6610 *
6611 * Create an XML RelaxNGs parse context for that memory buffer expected
6612 * to contain an XML RelaxNGs file.
6613 *
6614 * Returns the parser context or NULL in case of error
6615 */
6616xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006617xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6618{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006619 xmlRelaxNGParserCtxtPtr ret;
6620
6621 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006622 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006623
Daniel Veillard4c004142003-10-07 11:33:24 +00006624 ret =
6625 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006626 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006627 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006628 return (NULL);
6629 }
6630 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6631 ret->buffer = buffer;
6632 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006633 ret->error = xmlGenericError;
6634 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006635 return (ret);
6636}
6637
6638/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006639 * xmlRelaxNGNewDocParserCtxt:
6640 * @doc: a preparsed document tree
6641 *
6642 * Create an XML RelaxNGs parser context for that document.
6643 * Note: since the process of compiling a RelaxNG schemas modifies the
6644 * document, the @doc parameter is duplicated internally.
6645 *
6646 * Returns the parser context or NULL in case of error
6647 */
6648xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006649xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6650{
Daniel Veillard33300b42003-04-17 09:09:19 +00006651 xmlRelaxNGParserCtxtPtr ret;
6652 xmlDocPtr copy;
6653
6654 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006655 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006656 copy = xmlCopyDoc(doc, 1);
6657 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006658 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006659
Daniel Veillard4c004142003-10-07 11:33:24 +00006660 ret =
6661 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006662 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006663 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006664 return (NULL);
6665 }
6666 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6667 ret->document = copy;
Daniel Veillard42595322004-11-08 10:52:06 +00006668 ret->freedoc = 1;
Daniel Veillard33300b42003-04-17 09:09:19 +00006669 ret->userData = xmlGenericErrorContext;
6670 return (ret);
6671}
6672
6673/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006674 * xmlRelaxNGFreeParserCtxt:
6675 * @ctxt: the schema parser context
6676 *
6677 * Free the resources associated to the schema parser context
6678 */
6679void
Daniel Veillard4c004142003-10-07 11:33:24 +00006680xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6681{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006682 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006683 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006684 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006685 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006686 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006687 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006688 if (ctxt->interleaves != NULL)
6689 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006690 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006691 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006692 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006693 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006694 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006695 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006696 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006697 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006698 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006699 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006700
Daniel Veillard4c004142003-10-07 11:33:24 +00006701 for (i = 0; i < ctxt->defNr; i++)
6702 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6703 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006704 }
Daniel Veillard42595322004-11-08 10:52:06 +00006705 if ((ctxt->document != NULL) && (ctxt->freedoc))
6706 xmlFreeDoc(ctxt->document);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006707 xmlFree(ctxt);
6708}
6709
Daniel Veillard6eadf632003-01-23 18:29:16 +00006710/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006711 * xmlRelaxNGNormExtSpace:
6712 * @value: a value
6713 *
6714 * Removes the leading and ending spaces of the value
6715 * The string is modified "in situ"
6716 */
6717static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006718xmlRelaxNGNormExtSpace(xmlChar * value)
6719{
Daniel Veillardd2298792003-02-14 16:54:11 +00006720 xmlChar *start = value;
6721 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006722
Daniel Veillard4c004142003-10-07 11:33:24 +00006723 if (value == NULL)
6724 return;
6725
William M. Brack76e95df2003-10-18 16:20:14 +00006726 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006727 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006728 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006729 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006730 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006731 cur++;
6732 if (*cur == 0)
6733 return;
6734 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006735 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006736 cur++;
6737 if (*cur == 0) {
6738 *start = 0;
6739 return;
6740 }
6741 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006742 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006743 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006744 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006745 *start++ = *cur++;
6746 if (*cur == 0) {
6747 *start = 0;
6748 return;
6749 }
6750 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006751 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006752 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006753 if (*cur == 0) {
6754 *start = 0;
6755 return;
6756 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006757 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006758 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006759 }
6760}
6761
6762/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006763 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006764 * @ctxt: a Relax-NG parser context
6765 * @node: a Relax-NG node
6766 *
6767 * Check all the attributes on the given node
6768 */
6769static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006770xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6771{
Daniel Veillardd2298792003-02-14 16:54:11 +00006772 xmlAttrPtr cur, next;
6773
6774 cur = node->properties;
6775 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006776 next = cur->next;
6777 if ((cur->ns == NULL) ||
6778 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6779 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6780 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6781 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6782 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6783 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6784 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6785 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6786 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6787 "Attribute %s is not allowed on %s\n",
6788 cur->name, node->name);
6789 }
6790 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6791 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6792 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6793 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6794 "Attribute %s is not allowed on %s\n",
6795 cur->name, node->name);
6796 }
6797 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6798 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6799 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6800 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6801 "Attribute %s is not allowed on %s\n",
6802 cur->name, node->name);
6803 }
6804 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6805 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6806 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6807 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6808 "Attribute %s is not allowed on %s\n",
6809 cur->name, node->name);
6810 }
6811 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6812 xmlChar *val;
6813 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006814
Daniel Veillard4c004142003-10-07 11:33:24 +00006815 val = xmlNodeListGetString(node->doc, cur->children, 1);
6816 if (val != NULL) {
6817 if (val[0] != 0) {
6818 uri = xmlParseURI((const char *) val);
6819 if (uri == NULL) {
6820 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6821 "Attribute %s contains invalid URI %s\n",
6822 cur->name, val);
6823 } else {
6824 if (uri->scheme == NULL) {
6825 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6826 "Attribute %s URI %s is not absolute\n",
6827 cur->name, val);
6828 }
6829 if (uri->fragment != NULL) {
6830 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6831 "Attribute %s URI %s has a fragment ID\n",
6832 cur->name, val);
6833 }
6834 xmlFreeURI(uri);
6835 }
6836 }
6837 xmlFree(val);
6838 }
6839 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6840 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6841 "Unknown attribute %s on %s\n", cur->name,
6842 node->name);
6843 }
6844 }
6845 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006846 }
6847}
6848
6849/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006850 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006851 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006852 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006853 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006854 * Cleanup the subtree from unwanted nodes for parsing, resolve
6855 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006856 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006857static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006858xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6859{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006860 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006861
Daniel Veillard6eadf632003-01-23 18:29:16 +00006862 delete = NULL;
6863 cur = root;
6864 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006865 if (delete != NULL) {
6866 xmlUnlinkNode(delete);
6867 xmlFreeNode(delete);
6868 delete = NULL;
6869 }
6870 if (cur->type == XML_ELEMENT_NODE) {
6871 /*
6872 * Simplification 4.1. Annotations
6873 */
6874 if ((cur->ns == NULL) ||
6875 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6876 if ((cur->parent != NULL) &&
6877 (cur->parent->type == XML_ELEMENT_NODE) &&
6878 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6879 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6880 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6881 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6882 "element %s doesn't allow foreign elements\n",
6883 cur->parent->name, NULL);
6884 }
6885 delete = cur;
6886 goto skip_children;
6887 } else {
6888 xmlRelaxNGCleanupAttributes(ctxt, cur);
6889 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6890 xmlChar *href, *ns, *base, *URL;
6891 xmlRelaxNGDocumentPtr docu;
6892 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006893 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006894
Daniel Veillard4c004142003-10-07 11:33:24 +00006895 ns = xmlGetProp(cur, BAD_CAST "ns");
6896 if (ns == NULL) {
6897 tmp = cur->parent;
6898 while ((tmp != NULL) &&
6899 (tmp->type == XML_ELEMENT_NODE)) {
6900 ns = xmlGetProp(tmp, BAD_CAST "ns");
6901 if (ns != NULL)
6902 break;
6903 tmp = tmp->parent;
6904 }
6905 }
6906 href = xmlGetProp(cur, BAD_CAST "href");
6907 if (href == NULL) {
6908 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6909 "xmlRelaxNGParse: externalRef has no href attribute\n",
6910 NULL, NULL);
6911 delete = cur;
6912 goto skip_children;
6913 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006914 uri = xmlParseURI((const char *) href);
6915 if (uri == NULL) {
6916 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6917 "Incorrect URI for externalRef %s\n",
6918 href, NULL);
6919 if (href != NULL)
6920 xmlFree(href);
6921 delete = cur;
6922 goto skip_children;
6923 }
6924 if (uri->fragment != NULL) {
6925 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6926 "Fragment forbidden in URI for externalRef %s\n",
6927 href, NULL);
6928 xmlFreeURI(uri);
6929 if (href != NULL)
6930 xmlFree(href);
6931 delete = cur;
6932 goto skip_children;
6933 }
6934 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006935 base = xmlNodeGetBase(cur->doc, cur);
6936 URL = xmlBuildURI(href, base);
6937 if (URL == NULL) {
6938 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6939 "Failed to compute URL for externalRef %s\n",
6940 href, NULL);
6941 if (href != NULL)
6942 xmlFree(href);
6943 if (base != NULL)
6944 xmlFree(base);
6945 delete = cur;
6946 goto skip_children;
6947 }
6948 if (href != NULL)
6949 xmlFree(href);
6950 if (base != NULL)
6951 xmlFree(base);
6952 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6953 if (docu == NULL) {
6954 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6955 "Failed to load externalRef %s\n", URL,
6956 NULL);
6957 xmlFree(URL);
6958 delete = cur;
6959 goto skip_children;
6960 }
6961 if (ns != NULL)
6962 xmlFree(ns);
6963 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006964 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006965 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6966 xmlChar *href, *ns, *base, *URL;
6967 xmlRelaxNGIncludePtr incl;
6968 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006969
Daniel Veillard4c004142003-10-07 11:33:24 +00006970 href = xmlGetProp(cur, BAD_CAST "href");
6971 if (href == NULL) {
6972 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6973 "xmlRelaxNGParse: include has no href attribute\n",
6974 NULL, NULL);
6975 delete = cur;
6976 goto skip_children;
6977 }
6978 base = xmlNodeGetBase(cur->doc, cur);
6979 URL = xmlBuildURI(href, base);
6980 if (URL == NULL) {
6981 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6982 "Failed to compute URL for include %s\n",
6983 href, NULL);
6984 if (href != NULL)
6985 xmlFree(href);
6986 if (base != NULL)
6987 xmlFree(base);
6988 delete = cur;
6989 goto skip_children;
6990 }
6991 if (href != NULL)
6992 xmlFree(href);
6993 if (base != NULL)
6994 xmlFree(base);
6995 ns = xmlGetProp(cur, BAD_CAST "ns");
6996 if (ns == NULL) {
6997 tmp = cur->parent;
6998 while ((tmp != NULL) &&
6999 (tmp->type == XML_ELEMENT_NODE)) {
7000 ns = xmlGetProp(tmp, BAD_CAST "ns");
7001 if (ns != NULL)
7002 break;
7003 tmp = tmp->parent;
7004 }
7005 }
7006 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7007 if (ns != NULL)
7008 xmlFree(ns);
7009 if (incl == NULL) {
7010 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7011 "Failed to load include %s\n", URL,
7012 NULL);
7013 xmlFree(URL);
7014 delete = cur;
7015 goto skip_children;
7016 }
7017 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007018 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007019 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7020 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7021 {
7022 xmlChar *name, *ns;
7023 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007024
Daniel Veillard4c004142003-10-07 11:33:24 +00007025 /*
7026 * Simplification 4.8. name attribute of element
7027 * and attribute elements
7028 */
7029 name = xmlGetProp(cur, BAD_CAST "name");
7030 if (name != NULL) {
7031 if (cur->children == NULL) {
7032 text =
7033 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7034 name);
7035 } else {
7036 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007037
Daniel Veillard03a53c32004-10-26 16:06:51 +00007038 node = xmlNewDocNode(cur->doc, cur->ns,
7039 BAD_CAST "name", NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00007040 if (node != NULL) {
7041 xmlAddPrevSibling(cur->children, node);
7042 text = xmlNewText(name);
7043 xmlAddChild(node, text);
7044 text = node;
7045 }
7046 }
7047 if (text == NULL) {
7048 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7049 "Failed to create a name %s element\n",
7050 name, NULL);
7051 }
7052 xmlUnsetProp(cur, BAD_CAST "name");
7053 xmlFree(name);
7054 ns = xmlGetProp(cur, BAD_CAST "ns");
7055 if (ns != NULL) {
7056 if (text != NULL) {
7057 xmlSetProp(text, BAD_CAST "ns", ns);
7058 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7059 }
7060 xmlFree(ns);
7061 } else if (xmlStrEqual(cur->name,
7062 BAD_CAST "attribute")) {
7063 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7064 }
7065 }
7066 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7067 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7068 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7069 /*
7070 * Simplification 4.8. name attribute of element
7071 * and attribute elements
7072 */
7073 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7074 xmlNodePtr node;
7075 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007076
Daniel Veillard4c004142003-10-07 11:33:24 +00007077 node = cur->parent;
7078 while ((node != NULL) &&
7079 (node->type == XML_ELEMENT_NODE)) {
7080 ns = xmlGetProp(node, BAD_CAST "ns");
7081 if (ns != NULL) {
7082 break;
7083 }
7084 node = node->parent;
7085 }
7086 if (ns == NULL) {
7087 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7088 } else {
7089 xmlSetProp(cur, BAD_CAST "ns", ns);
7090 xmlFree(ns);
7091 }
7092 }
7093 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7094 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007095
Daniel Veillard4c004142003-10-07 11:33:24 +00007096 /*
7097 * Simplification: 4.10. QNames
7098 */
7099 name = xmlNodeGetContent(cur);
7100 if (name != NULL) {
7101 local = xmlSplitQName2(name, &prefix);
7102 if (local != NULL) {
7103 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007104
Daniel Veillard4c004142003-10-07 11:33:24 +00007105 ns = xmlSearchNs(cur->doc, cur, prefix);
7106 if (ns == NULL) {
7107 xmlRngPErr(ctxt, cur,
7108 XML_RNGP_PREFIX_UNDEFINED,
7109 "xmlRelaxNGParse: no namespace for prefix %s\n",
7110 prefix, NULL);
7111 } else {
7112 xmlSetProp(cur, BAD_CAST "ns",
7113 ns->href);
7114 xmlNodeSetContent(cur, local);
7115 }
7116 xmlFree(local);
7117 xmlFree(prefix);
7118 }
7119 xmlFree(name);
7120 }
7121 }
7122 /*
7123 * 4.16
7124 */
7125 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7126 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7127 xmlRngPErr(ctxt, cur,
7128 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7129 "Found nsName/except//nsName forbidden construct\n",
7130 NULL, NULL);
7131 }
7132 }
7133 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7134 (cur != root)) {
7135 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007136
Daniel Veillard4c004142003-10-07 11:33:24 +00007137 /*
7138 * 4.16
7139 */
7140 if ((cur->parent != NULL) &&
7141 (xmlStrEqual
7142 (cur->parent->name, BAD_CAST "anyName"))) {
7143 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7144 xmlRelaxNGCleanupTree(ctxt, cur);
7145 ctxt->flags = oldflags;
7146 goto skip_children;
7147 } else if ((cur->parent != NULL) &&
7148 (xmlStrEqual
7149 (cur->parent->name, BAD_CAST "nsName"))) {
7150 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7151 xmlRelaxNGCleanupTree(ctxt, cur);
7152 ctxt->flags = oldflags;
7153 goto skip_children;
7154 }
7155 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7156 /*
7157 * 4.16
7158 */
7159 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7160 xmlRngPErr(ctxt, cur,
7161 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7162 "Found anyName/except//anyName forbidden construct\n",
7163 NULL, NULL);
7164 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7165 xmlRngPErr(ctxt, cur,
7166 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7167 "Found nsName/except//anyName forbidden construct\n",
7168 NULL, NULL);
7169 }
7170 }
7171 /*
7172 * Thisd is not an else since "include" is transformed
7173 * into a div
7174 */
7175 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7176 xmlChar *ns;
7177 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007178
Daniel Veillard4c004142003-10-07 11:33:24 +00007179 /*
7180 * implements rule 4.11
7181 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007182
Daniel Veillard4c004142003-10-07 11:33:24 +00007183 ns = xmlGetProp(cur, BAD_CAST "ns");
7184
7185 child = cur->children;
7186 ins = cur;
7187 while (child != NULL) {
7188 if (ns != NULL) {
7189 if (!xmlHasProp(child, BAD_CAST "ns")) {
7190 xmlSetProp(child, BAD_CAST "ns", ns);
7191 }
7192 }
7193 tmp = child->next;
7194 xmlUnlinkNode(child);
7195 ins = xmlAddNextSibling(ins, child);
7196 child = tmp;
7197 }
7198 if (ns != NULL)
7199 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007200 /*
7201 * Since we are about to delete cur, if it's nsDef is non-NULL we
7202 * need to preserve it (it contains the ns definitions for the
7203 * children we just moved). We'll just stick it on to the end
7204 * of cur->parent's list, since it's never going to be re-serialized
7205 * (bug 143738).
7206 */
7207 if (cur->nsDef != NULL) {
7208 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7209 while (parDef->next != NULL)
7210 parDef = parDef->next;
7211 parDef->next = cur->nsDef;
7212 cur->nsDef = NULL;
7213 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007214 delete = cur;
7215 goto skip_children;
7216 }
7217 }
7218 }
7219 /*
7220 * Simplification 4.2 whitespaces
7221 */
7222 else if ((cur->type == XML_TEXT_NODE) ||
7223 (cur->type == XML_CDATA_SECTION_NODE)) {
7224 if (IS_BLANK_NODE(cur)) {
7225 if (cur->parent->type == XML_ELEMENT_NODE) {
7226 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7227 &&
7228 (!xmlStrEqual
7229 (cur->parent->name, BAD_CAST "param")))
7230 delete = cur;
7231 } else {
7232 delete = cur;
7233 goto skip_children;
7234 }
7235 }
7236 } else {
7237 delete = cur;
7238 goto skip_children;
7239 }
7240
7241 /*
7242 * Skip to next node
7243 */
7244 if (cur->children != NULL) {
7245 if ((cur->children->type != XML_ENTITY_DECL) &&
7246 (cur->children->type != XML_ENTITY_REF_NODE) &&
7247 (cur->children->type != XML_ENTITY_NODE)) {
7248 cur = cur->children;
7249 continue;
7250 }
7251 }
7252 skip_children:
7253 if (cur->next != NULL) {
7254 cur = cur->next;
7255 continue;
7256 }
7257
7258 do {
7259 cur = cur->parent;
7260 if (cur == NULL)
7261 break;
7262 if (cur == root) {
7263 cur = NULL;
7264 break;
7265 }
7266 if (cur->next != NULL) {
7267 cur = cur->next;
7268 break;
7269 }
7270 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007271 }
7272 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007273 xmlUnlinkNode(delete);
7274 xmlFreeNode(delete);
7275 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007276 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007277}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007278
Daniel Veillardc5312d72003-02-21 17:14:10 +00007279/**
7280 * xmlRelaxNGCleanupDoc:
7281 * @ctxt: a Relax-NG parser context
7282 * @doc: an xmldocPtr document pointer
7283 *
7284 * Cleanup the document from unwanted nodes for parsing, resolve
7285 * Include and externalRef lookups.
7286 *
7287 * Returns the cleaned up document or NULL in case of error
7288 */
7289static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007290xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7291{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007292 xmlNodePtr root;
7293
7294 /*
7295 * Extract the root
7296 */
7297 root = xmlDocGetRootElement(doc);
7298 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007299 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7300 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007301 return (NULL);
7302 }
7303 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007304 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007305}
7306
7307/**
7308 * xmlRelaxNGParse:
7309 * @ctxt: a Relax-NG parser context
7310 *
7311 * parse a schema definition resource and build an internal
7312 * XML Shema struture which can be used to validate instances.
7313 * *WARNING* this interface is highly subject to change
7314 *
7315 * Returns the internal XML RelaxNG structure built from the resource or
7316 * NULL in case of error
7317 */
7318xmlRelaxNGPtr
7319xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7320{
7321 xmlRelaxNGPtr ret = NULL;
7322 xmlDocPtr doc;
7323 xmlNodePtr root;
7324
7325 xmlRelaxNGInitTypes();
7326
7327 if (ctxt == NULL)
7328 return (NULL);
7329
7330 /*
7331 * First step is to parse the input document into an DOM/Infoset
7332 */
7333 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007334 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007335 if (doc == NULL) {
7336 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7337 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7338 NULL);
7339 return (NULL);
7340 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007341 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007342 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007343 if (doc == NULL) {
7344 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7345 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7346 NULL);
7347 return (NULL);
7348 }
7349 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7350 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007351 } else if (ctxt->document != NULL) {
7352 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007353 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007354 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7355 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7356 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007357 }
7358 ctxt->document = doc;
7359
7360 /*
7361 * Some preprocessing of the document content
7362 */
7363 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7364 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007365 xmlFreeDoc(ctxt->document);
7366 ctxt->document = NULL;
7367 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007368 }
7369
Daniel Veillard6eadf632003-01-23 18:29:16 +00007370 /*
7371 * Then do the parsing for good
7372 */
7373 root = xmlDocGetRootElement(doc);
7374 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007375 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7376 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7377 ctxt->URL, NULL);
7378 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007379 return (NULL);
7380 }
7381 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007382 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007383 xmlFreeDoc(doc);
7384 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007385 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007386
7387 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007388 * Check the ref/defines links
7389 */
7390 /*
7391 * try to preprocess interleaves
7392 */
7393 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007394 xmlHashScan(ctxt->interleaves,
7395 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007396 }
7397
7398 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007399 * if there was a parsing error return NULL
7400 */
7401 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007402 xmlRelaxNGFree(ret);
7403 ctxt->document = NULL;
7404 xmlFreeDoc(doc);
7405 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007406 }
7407
7408 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007409 * try to compile (parts of) the schemas
7410 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007411 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7412 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007413 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007414
Daniel Veillard4c004142003-10-07 11:33:24 +00007415 def = xmlRelaxNGNewDefine(ctxt, NULL);
7416 if (def != NULL) {
7417 def->type = XML_RELAXNG_START;
7418 def->content = ret->topgrammar->start;
7419 ret->topgrammar->start = def;
7420 }
7421 }
7422 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007423 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007424
7425 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007426 * Transfer the pointer for cleanup at the schema level.
7427 */
7428 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007429 ctxt->document = NULL;
7430 ret->documents = ctxt->documents;
7431 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007432
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007433 ret->includes = ctxt->includes;
7434 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007435 ret->defNr = ctxt->defNr;
7436 ret->defTab = ctxt->defTab;
7437 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007438 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007439 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007440
7441 return (ret);
7442}
Daniel Veillard4c004142003-10-07 11:33:24 +00007443
Daniel Veillard6eadf632003-01-23 18:29:16 +00007444/**
7445 * xmlRelaxNGSetParserErrors:
7446 * @ctxt: a Relax-NG validation context
7447 * @err: the error callback
7448 * @warn: the warning callback
7449 * @ctx: contextual data for the callbacks
7450 *
7451 * Set the callback functions used to handle errors for a validation context
7452 */
7453void
7454xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007455 xmlRelaxNGValidityErrorFunc err,
7456 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7457{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007458 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007459 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007460 ctxt->error = err;
7461 ctxt->warning = warn;
7462 ctxt->userData = ctx;
7463}
Daniel Veillard409a8142003-07-18 15:16:57 +00007464
7465/**
7466 * xmlRelaxNGGetParserErrors:
7467 * @ctxt: a Relax-NG validation context
7468 * @err: the error callback result
7469 * @warn: the warning callback result
7470 * @ctx: contextual data for the callbacks result
7471 *
7472 * Get the callback information used to handle errors for a validation context
7473 *
7474 * Returns -1 in case of failure, 0 otherwise.
7475 */
7476int
7477xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007478 xmlRelaxNGValidityErrorFunc * err,
7479 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7480{
Daniel Veillard409a8142003-07-18 15:16:57 +00007481 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007482 return (-1);
7483 if (err != NULL)
7484 *err = ctxt->error;
7485 if (warn != NULL)
7486 *warn = ctxt->warning;
7487 if (ctx != NULL)
7488 *ctx = ctxt->userData;
7489 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007490}
7491
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007492#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007493
Daniel Veillard6eadf632003-01-23 18:29:16 +00007494/************************************************************************
7495 * *
7496 * Dump back a compiled form *
7497 * *
7498 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007499static void xmlRelaxNGDumpDefine(FILE * output,
7500 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007501
7502/**
7503 * xmlRelaxNGDumpDefines:
7504 * @output: the file output
7505 * @defines: a list of define structures
7506 *
7507 * Dump a RelaxNG structure back
7508 */
7509static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007510xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7511{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007512 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007513 xmlRelaxNGDumpDefine(output, defines);
7514 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007515 }
7516}
7517
7518/**
7519 * xmlRelaxNGDumpDefine:
7520 * @output: the file output
7521 * @define: a define structure
7522 *
7523 * Dump a RelaxNG structure back
7524 */
7525static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007526xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7527{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007528 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007529 return;
7530 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007531 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007532 fprintf(output, "<empty/>\n");
7533 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007534 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007535 fprintf(output, "<notAllowed/>\n");
7536 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007537 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007538 fprintf(output, "<text/>\n");
7539 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007540 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007541 fprintf(output, "<element>\n");
7542 if (define->name != NULL) {
7543 fprintf(output, "<name");
7544 if (define->ns != NULL)
7545 fprintf(output, " ns=\"%s\"", define->ns);
7546 fprintf(output, ">%s</name>\n", define->name);
7547 }
7548 xmlRelaxNGDumpDefines(output, define->attrs);
7549 xmlRelaxNGDumpDefines(output, define->content);
7550 fprintf(output, "</element>\n");
7551 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007552 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007553 fprintf(output, "<list>\n");
7554 xmlRelaxNGDumpDefines(output, define->content);
7555 fprintf(output, "</list>\n");
7556 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007557 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007558 fprintf(output, "<oneOrMore>\n");
7559 xmlRelaxNGDumpDefines(output, define->content);
7560 fprintf(output, "</oneOrMore>\n");
7561 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007562 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007563 fprintf(output, "<zeroOrMore>\n");
7564 xmlRelaxNGDumpDefines(output, define->content);
7565 fprintf(output, "</zeroOrMore>\n");
7566 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007567 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007568 fprintf(output, "<choice>\n");
7569 xmlRelaxNGDumpDefines(output, define->content);
7570 fprintf(output, "</choice>\n");
7571 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007572 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007573 fprintf(output, "<group>\n");
7574 xmlRelaxNGDumpDefines(output, define->content);
7575 fprintf(output, "</group>\n");
7576 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007577 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007578 fprintf(output, "<interleave>\n");
7579 xmlRelaxNGDumpDefines(output, define->content);
7580 fprintf(output, "</interleave>\n");
7581 break;
7582 case XML_RELAXNG_OPTIONAL:
7583 fprintf(output, "<optional>\n");
7584 xmlRelaxNGDumpDefines(output, define->content);
7585 fprintf(output, "</optional>\n");
7586 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007587 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007588 fprintf(output, "<attribute>\n");
7589 xmlRelaxNGDumpDefines(output, define->content);
7590 fprintf(output, "</attribute>\n");
7591 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007592 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007593 fprintf(output, "<define");
7594 if (define->name != NULL)
7595 fprintf(output, " name=\"%s\"", define->name);
7596 fprintf(output, ">\n");
7597 xmlRelaxNGDumpDefines(output, define->content);
7598 fprintf(output, "</define>\n");
7599 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007600 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007601 fprintf(output, "<ref");
7602 if (define->name != NULL)
7603 fprintf(output, " name=\"%s\"", define->name);
7604 fprintf(output, ">\n");
7605 xmlRelaxNGDumpDefines(output, define->content);
7606 fprintf(output, "</ref>\n");
7607 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007608 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007609 fprintf(output, "<parentRef");
7610 if (define->name != NULL)
7611 fprintf(output, " name=\"%s\"", define->name);
7612 fprintf(output, ">\n");
7613 xmlRelaxNGDumpDefines(output, define->content);
7614 fprintf(output, "</parentRef>\n");
7615 break;
7616 case XML_RELAXNG_EXTERNALREF:
7617 fprintf(output, "<externalRef>");
7618 xmlRelaxNGDumpDefines(output, define->content);
7619 fprintf(output, "</externalRef>\n");
7620 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007621 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007622 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007623 TODO break;
7624 case XML_RELAXNG_START:
7625 case XML_RELAXNG_EXCEPT:
7626 case XML_RELAXNG_PARAM:
7627 TODO break;
7628 case XML_RELAXNG_NOOP:
7629 xmlRelaxNGDumpDefines(output, define->content);
7630 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007631 }
7632}
Daniel Veillard4c004142003-10-07 11:33:24 +00007633
Daniel Veillard6eadf632003-01-23 18:29:16 +00007634/**
7635 * xmlRelaxNGDumpGrammar:
7636 * @output: the file output
7637 * @grammar: a grammar structure
7638 * @top: is this a top grammar
7639 *
7640 * Dump a RelaxNG structure back
7641 */
7642static void
7643xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7644{
7645 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007646 return;
7647
Daniel Veillard6eadf632003-01-23 18:29:16 +00007648 fprintf(output, "<grammar");
7649 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007650 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7651 switch (grammar->combine) {
7652 case XML_RELAXNG_COMBINE_UNDEFINED:
7653 break;
7654 case XML_RELAXNG_COMBINE_CHOICE:
7655 fprintf(output, " combine=\"choice\"");
7656 break;
7657 case XML_RELAXNG_COMBINE_INTERLEAVE:
7658 fprintf(output, " combine=\"interleave\"");
7659 break;
7660 default:
7661 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007662 }
7663 fprintf(output, ">\n");
7664 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007665 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007666 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007667 fprintf(output, "<start>\n");
7668 xmlRelaxNGDumpDefine(output, grammar->start);
7669 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007670 }
7671 /* TODO ? Dump the defines ? */
7672 fprintf(output, "</grammar>\n");
7673}
7674
7675/**
7676 * xmlRelaxNGDump:
7677 * @output: the file output
7678 * @schema: a schema structure
7679 *
7680 * Dump a RelaxNG structure back
7681 */
7682void
7683xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7684{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007685 if (output == NULL)
7686 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007687 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007688 fprintf(output, "RelaxNG empty or failed to compile\n");
7689 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007690 }
7691 fprintf(output, "RelaxNG: ");
7692 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007693 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007694 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007695 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007696 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007697 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007698 }
7699 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007700 fprintf(output, "RelaxNG has no top grammar\n");
7701 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007702 }
7703 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7704}
7705
Daniel Veillardfebcca42003-02-16 15:44:18 +00007706/**
7707 * xmlRelaxNGDumpTree:
7708 * @output: the file output
7709 * @schema: a schema structure
7710 *
7711 * Dump the transformed RelaxNG tree.
7712 */
7713void
7714xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7715{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007716 if (output == NULL)
7717 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007718 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007719 fprintf(output, "RelaxNG empty or failed to compile\n");
7720 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007721 }
7722 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007723 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007724 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007725 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007726 }
7727}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007728#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007729
Daniel Veillard6eadf632003-01-23 18:29:16 +00007730/************************************************************************
7731 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007732 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007733 * *
7734 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007735static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7736 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007737
7738/**
7739 * xmlRelaxNGValidateCompiledCallback:
7740 * @exec: the regular expression instance
7741 * @token: the token which matched
7742 * @transdata: callback data, the define for the subelement if available
7743 @ @inputdata: callback data, the Relax NG validation context
7744 *
7745 * Handle the callback and if needed validate the element children.
7746 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007747static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007748xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007749 const xmlChar * token,
7750 void *transdata, void *inputdata)
7751{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007752 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7753 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7754 int ret;
7755
7756#ifdef DEBUG_COMPILE
7757 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007758 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007759#endif
7760 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007761 fprintf(stderr, "callback on %s missing context\n", token);
7762 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7763 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7764 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007765 }
7766 if (define == NULL) {
7767 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007768 return;
7769 fprintf(stderr, "callback on %s missing define\n", token);
7770 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7771 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7772 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007773 }
7774 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007775 fprintf(stderr, "callback on %s missing info\n", token);
7776 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7777 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7778 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007779 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007780 fprintf(stderr, "callback on %s define is not element\n", token);
7781 if (ctxt->errNo == XML_RELAXNG_OK)
7782 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7783 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007784 }
7785 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007786 if (ret != 0)
7787 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007788}
7789
7790/**
7791 * xmlRelaxNGValidateCompiledContent:
7792 * @ctxt: the RelaxNG validation context
7793 * @regexp: the regular expression as compiled
7794 * @content: list of children to test against the regexp
7795 *
7796 * Validate the content model of an element or start using the regexp
7797 *
7798 * Returns 0 in case of success, -1 in case of error.
7799 */
7800static int
7801xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007802 xmlRegexpPtr regexp, xmlNodePtr content)
7803{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007804 xmlRegExecCtxtPtr exec;
7805 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007806 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007807 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007808
7809 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007810 return (-1);
7811 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007812 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007813 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007814 cur = content;
7815 while (cur != NULL) {
7816 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007817 switch (cur->type) {
7818 case XML_TEXT_NODE:
7819 case XML_CDATA_SECTION_NODE:
7820 if (xmlIsBlankNode(cur))
7821 break;
7822 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7823 if (ret < 0) {
7824 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7825 cur->parent->name);
7826 }
7827 break;
7828 case XML_ELEMENT_NODE:
7829 if (cur->ns != NULL) {
7830 ret = xmlRegExecPushString2(exec, cur->name,
7831 cur->ns->href, ctxt);
7832 } else {
7833 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7834 }
7835 if (ret < 0) {
7836 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7837 }
7838 break;
7839 default:
7840 break;
7841 }
7842 if (ret < 0)
7843 break;
7844 /*
7845 * Switch to next element
7846 */
7847 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007848 }
7849 ret = xmlRegExecPushString(exec, NULL, NULL);
7850 if (ret == 1) {
7851 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007852 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007853 } else if (ret == 0) {
7854 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007855 * TODO: get some of the names needed to exit the current state of exec
7856 */
7857 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7858 ret = -1;
7859 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7860 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007861 } else {
7862 ret = -1;
7863 }
7864 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007865 /*
7866 * There might be content model errors outside of the pure
7867 * regexp validation, e.g. for attribute values.
7868 */
7869 if ((ret == 0) && (ctxt->perr != 0)) {
7870 ret = ctxt->perr;
7871 }
7872 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007873 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007874}
7875
7876/************************************************************************
7877 * *
7878 * Progressive validation of when possible *
7879 * *
7880 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007881static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7882 xmlRelaxNGDefinePtr defines);
7883static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007884 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007885static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007886
7887/**
7888 * xmlRelaxNGElemPush:
7889 * @ctxt: the validation context
7890 * @exec: the regexp runtime for the new content model
7891 *
7892 * Push a new regexp for the current node content model on the stack
7893 *
7894 * Returns 0 in case of success and -1 in case of error.
7895 */
7896static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007897xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7898{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007899 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007900 ctxt->elemMax = 10;
7901 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7902 sizeof
7903 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007904 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007905 xmlRngVErrMemory(ctxt, "validating\n");
7906 return (-1);
7907 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007908 }
7909 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007910 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007911 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007912 ctxt->elemMax *
7913 sizeof
7914 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007915 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007916 xmlRngVErrMemory(ctxt, "validating\n");
7917 return (-1);
7918 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007919 }
7920 ctxt->elemTab[ctxt->elemNr++] = exec;
7921 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007922 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007923}
7924
7925/**
7926 * xmlRelaxNGElemPop:
7927 * @ctxt: the validation context
7928 *
7929 * Pop the regexp of the current node content model from the stack
7930 *
7931 * Returns the exec or NULL if empty
7932 */
7933static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007934xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7935{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007936 xmlRegExecCtxtPtr ret;
7937
Daniel Veillard4c004142003-10-07 11:33:24 +00007938 if (ctxt->elemNr <= 0)
7939 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007940 ctxt->elemNr--;
7941 ret = ctxt->elemTab[ctxt->elemNr];
7942 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007943 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007944 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7945 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007946 ctxt->elem = NULL;
7947 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007948}
7949
7950/**
7951 * xmlRelaxNGValidateProgressiveCallback:
7952 * @exec: the regular expression instance
7953 * @token: the token which matched
7954 * @transdata: callback data, the define for the subelement if available
7955 @ @inputdata: callback data, the Relax NG validation context
7956 *
7957 * Handle the callback and if needed validate the element children.
7958 * some of the in/out informations are passed via the context in @inputdata.
7959 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007960static void
7961xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7962 ATTRIBUTE_UNUSED,
7963 const xmlChar * token,
7964 void *transdata, void *inputdata)
7965{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007966 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7967 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007968 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007969 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007970 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007971
7972#ifdef DEBUG_PROGRESSIVE
7973 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007974 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007975#endif
7976 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007977 fprintf(stderr, "callback on %s missing context\n", token);
7978 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007979 }
7980 ctxt->pstate = 1;
7981 if (define == NULL) {
7982 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007983 return;
7984 fprintf(stderr, "callback on %s missing define\n", token);
7985 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7986 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7987 ctxt->pstate = -1;
7988 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007989 }
7990 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007991 fprintf(stderr, "callback on %s missing info\n", token);
7992 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7993 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7994 ctxt->pstate = -1;
7995 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007996 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007997 fprintf(stderr, "callback on %s define is not element\n", token);
7998 if (ctxt->errNo == XML_RELAXNG_OK)
7999 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8000 ctxt->pstate = -1;
8001 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008002 }
8003 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008004 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8005 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8006 xmlRelaxNGDumpValidError(ctxt);
8007 ctxt->pstate = -1;
8008 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008009 }
8010 if (define->contModel == NULL) {
8011 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008012 * this node cannot be validated in a streamable fashion
8013 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00008014#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008015 xmlGenericError(xmlGenericErrorContext,
8016 "Element '%s' validation is not streamable\n",
8017 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008018#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008019 ctxt->pstate = 0;
8020 ctxt->pdef = define;
8021 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008022 }
8023 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008024 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008025 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008026 ctxt->pstate = -1;
8027 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008028 }
8029 xmlRelaxNGElemPush(ctxt, exec);
8030
8031 /*
8032 * Validate the attributes part of the content.
8033 */
8034 state = xmlRelaxNGNewValidState(ctxt, node);
8035 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008036 ctxt->pstate = -1;
8037 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008038 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008039 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008040 ctxt->state = state;
8041 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008042 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8043 if (ret != 0) {
8044 ctxt->pstate = -1;
8045 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8046 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008047 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008048 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008049 ctxt->state->seq = NULL;
8050 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8051 if (ret != 0) {
8052 ctxt->pstate = -1;
8053 }
8054 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008055 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008056 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008057
8058 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008059
Daniel Veillard4c004142003-10-07 11:33:24 +00008060 for (i = 0; i < ctxt->states->nbState; i++) {
8061 state = ctxt->states->tabState[i];
8062 ctxt->state = state;
8063 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008064
Daniel Veillard4c004142003-10-07 11:33:24 +00008065 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8066 tmp = 0;
8067 break;
8068 }
8069 }
8070 if (tmp != 0) {
8071 /*
8072 * validation error, log the message for the "best" one
8073 */
8074 ctxt->flags |= FLAGS_IGNORABLE;
8075 xmlRelaxNGLogBestError(ctxt);
8076 }
8077 for (i = 0; i < ctxt->states->nbState; i++) {
8078 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8079 }
8080 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8081 ctxt->states = NULL;
8082 if ((ret == 0) && (tmp == -1))
8083 ctxt->pstate = -1;
8084 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008085 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008086 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008087 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8088 xmlRelaxNGDumpValidError(ctxt);
8089 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008090 }
8091 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008092}
8093
8094/**
8095 * xmlRelaxNGValidatePushElement:
8096 * @ctxt: the validation context
8097 * @doc: a document instance
8098 * @elem: an element instance
8099 *
8100 * Push a new element start on the RelaxNG validation stack.
8101 *
8102 * returns 1 if no validation problem was found or 0 if validating the
8103 * element requires a full node, and -1 in case of error.
8104 */
8105int
Daniel Veillard33300b42003-04-17 09:09:19 +00008106xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8107 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008108 xmlNodePtr elem)
8109{
8110 int ret = 1;
8111
8112 if ((ctxt == NULL) || (elem == NULL))
8113 return (-1);
8114
8115#ifdef DEBUG_PROGRESSIVE
8116 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8117#endif
8118 if (ctxt->elem == 0) {
8119 xmlRelaxNGPtr schema;
8120 xmlRelaxNGGrammarPtr grammar;
8121 xmlRegExecCtxtPtr exec;
8122 xmlRelaxNGDefinePtr define;
8123
8124 schema = ctxt->schema;
8125 if (schema == NULL) {
8126 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8127 return (-1);
8128 }
8129 grammar = schema->topgrammar;
8130 if ((grammar == NULL) || (grammar->start == NULL)) {
8131 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8132 return (-1);
8133 }
8134 define = grammar->start;
8135 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008136 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008137 return (0);
8138 }
8139 exec = xmlRegNewExecCtxt(define->contModel,
8140 xmlRelaxNGValidateProgressiveCallback,
8141 ctxt);
8142 if (exec == NULL) {
8143 return (-1);
8144 }
8145 xmlRelaxNGElemPush(ctxt, exec);
8146 }
8147 ctxt->pnode = elem;
8148 ctxt->pstate = 0;
8149 if (elem->ns != NULL) {
8150 ret =
8151 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8152 ctxt);
8153 } else {
8154 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8155 }
8156 if (ret < 0) {
8157 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8158 } else {
8159 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008160 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008161 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008162 ret = -1;
8163 else
8164 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008165 }
8166#ifdef DEBUG_PROGRESSIVE
8167 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008168 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8169 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008170#endif
8171 return (ret);
8172}
8173
8174/**
8175 * xmlRelaxNGValidatePushCData:
8176 * @ctxt: the RelaxNG validation context
8177 * @data: some character data read
8178 * @len: the lenght of the data
8179 *
8180 * check the CData parsed for validation in the current stack
8181 *
8182 * returns 1 if no validation problem was found or -1 otherwise
8183 */
8184int
8185xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008186 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008187{
8188 int ret = 1;
8189
8190 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8191 return (-1);
8192
8193#ifdef DEBUG_PROGRESSIVE
8194 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8195#endif
8196
8197 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008198 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008199 break;
8200 data++;
8201 }
8202 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008203 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008204
8205 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8206 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008207 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008208#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008209 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008210#endif
8211
Daniel Veillard4c004142003-10-07 11:33:24 +00008212 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008213 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008214 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008215}
8216
8217/**
8218 * xmlRelaxNGValidatePopElement:
8219 * @ctxt: the RelaxNG validation context
8220 * @doc: a document instance
8221 * @elem: an element instance
8222 *
8223 * Pop the element end from the RelaxNG validation stack.
8224 *
8225 * returns 1 if no validation problem was found or 0 otherwise
8226 */
8227int
8228xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8229 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008230 xmlNodePtr elem)
8231{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008232 int ret;
8233 xmlRegExecCtxtPtr exec;
8234
Daniel Veillard4c004142003-10-07 11:33:24 +00008235 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8236 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008237#ifdef DEBUG_PROGRESSIVE
8238 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8239#endif
8240 /*
8241 * verify that we reached a terminal state of the content model.
8242 */
8243 exec = xmlRelaxNGElemPop(ctxt);
8244 ret = xmlRegExecPushString(exec, NULL, NULL);
8245 if (ret == 0) {
8246 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008247 * TODO: get some of the names needed to exit the current state of exec
8248 */
8249 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8250 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008251 } else if (ret < 0) {
8252 ret = -1;
8253 } else {
8254 ret = 1;
8255 }
8256 xmlRegFreeExecCtxt(exec);
8257#ifdef DEBUG_PROGRESSIVE
8258 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008259 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8260 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008261#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008262 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008263}
8264
8265/**
8266 * xmlRelaxNGValidateFullElement:
8267 * @ctxt: the validation context
8268 * @doc: a document instance
8269 * @elem: an element instance
8270 *
8271 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8272 * 0 and the content of the node has been expanded.
8273 *
8274 * returns 1 if no validation problem was found or -1 in case of error.
8275 */
8276int
Daniel Veillard33300b42003-04-17 09:09:19 +00008277xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8278 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008279 xmlNodePtr elem)
8280{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008281 int ret;
8282 xmlRelaxNGValidStatePtr state;
8283
Daniel Veillard4c004142003-10-07 11:33:24 +00008284 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8285 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008286#ifdef DEBUG_PROGRESSIVE
8287 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8288#endif
8289 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8290 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008291 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008292 }
8293 state->seq = elem;
8294 ctxt->state = state;
8295 ctxt->errNo = XML_RELAXNG_OK;
8296 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008297 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8298 ret = -1;
8299 else
8300 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008301 xmlRelaxNGFreeValidState(ctxt, state);
8302 ctxt->state = NULL;
8303#ifdef DEBUG_PROGRESSIVE
8304 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008305 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8306 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008307#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008308 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008309}
8310
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008311/************************************************************************
8312 * *
8313 * Generic interpreted validation implementation *
8314 * *
8315 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008316static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8317 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008318
8319/**
8320 * xmlRelaxNGSkipIgnored:
8321 * @ctxt: a schema validation context
8322 * @node: the top node.
8323 *
8324 * Skip ignorable nodes in that context
8325 *
8326 * Returns the new sibling or NULL in case of error.
8327 */
8328static xmlNodePtr
8329xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008330 xmlNodePtr node)
8331{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008332 /*
8333 * TODO complete and handle entities
8334 */
8335 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008336 ((node->type == XML_COMMENT_NODE) ||
8337 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008338 (node->type == XML_XINCLUDE_START) ||
8339 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008340 (((node->type == XML_TEXT_NODE) ||
8341 (node->type == XML_CDATA_SECTION_NODE)) &&
8342 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8343 (IS_BLANK_NODE(node)))))) {
8344 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008345 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008346 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008347}
8348
8349/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008350 * xmlRelaxNGNormalize:
8351 * @ctxt: a schema validation context
8352 * @str: the string to normalize
8353 *
8354 * Implements the normalizeWhiteSpace( s ) function from
8355 * section 6.2.9 of the spec
8356 *
8357 * Returns the new string or NULL in case of error.
8358 */
8359static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008360xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8361{
Daniel Veillardedc91922003-01-26 00:52:04 +00008362 xmlChar *ret, *p;
8363 const xmlChar *tmp;
8364 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008365
Daniel Veillardedc91922003-01-26 00:52:04 +00008366 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008367 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008368 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008369 while (*tmp != 0)
8370 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008371 len = tmp - str;
8372
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008373 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008374 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008375 xmlRngVErrMemory(ctxt, "validating\n");
8376 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008377 }
8378 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008379 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008380 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008381 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008382 if (IS_BLANK_CH(*str)) {
8383 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008384 str++;
8385 if (*str == 0)
8386 break;
8387 *p++ = ' ';
8388 } else
8389 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008390 }
8391 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008392 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008393}
8394
8395/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008396 * xmlRelaxNGValidateDatatype:
8397 * @ctxt: a Relax-NG validation context
8398 * @value: the string value
8399 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008400 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008401 *
8402 * Validate the given value against the dataype
8403 *
8404 * Returns 0 if the validation succeeded or an error code.
8405 */
8406static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008407xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8408 const xmlChar * value,
8409 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8410{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008411 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008412 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008413 void *result = NULL;
8414 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008415
8416 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008417 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008418 }
8419 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008420 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008421 if ((define->attrs != NULL) &&
8422 (define->attrs->type == XML_RELAXNG_PARAM)) {
8423 ret =
8424 lib->check(lib->data, define->name, value, &result, node);
8425 } else {
8426 ret = lib->check(lib->data, define->name, value, NULL, node);
8427 }
8428 } else
8429 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008430 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008431 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8432 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8433 lib->freef(lib->data, result);
8434 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008435 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008436 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008437 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008438 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008439 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008440 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8441 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008442 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008443 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008444 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008445 if (lib->facet != NULL) {
8446 tmp = lib->facet(lib->data, define->name, cur->name,
8447 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008448 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008449 ret = -1;
8450 }
8451 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008452 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008453 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008454 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008455
Daniel Veillard4c004142003-10-07 11:33:24 +00008456 oldvalue = ctxt->state->value;
8457 oldendvalue = ctxt->state->endvalue;
8458 ctxt->state->value = (xmlChar *) value;
8459 ctxt->state->endvalue = NULL;
8460 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8461 ctxt->state->value = (xmlChar *) oldvalue;
8462 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008463 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008464 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008465 lib->freef(lib->data, result);
8466 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008467}
8468
8469/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008470 * xmlRelaxNGNextValue:
8471 * @ctxt: a Relax-NG validation context
8472 *
8473 * Skip to the next value when validating within a list
8474 *
8475 * Returns 0 if the operation succeeded or an error code.
8476 */
8477static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008478xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8479{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008480 xmlChar *cur;
8481
8482 cur = ctxt->state->value;
8483 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008484 ctxt->state->value = NULL;
8485 ctxt->state->endvalue = NULL;
8486 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008487 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008488 while (*cur != 0)
8489 cur++;
8490 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8491 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008492 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008493 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008494 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008495 ctxt->state->value = cur;
8496 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008497}
8498
8499/**
8500 * xmlRelaxNGValidateValueList:
8501 * @ctxt: a Relax-NG validation context
8502 * @defines: the list of definitions to verify
8503 *
8504 * Validate the given set of definitions for the current value
8505 *
8506 * Returns 0 if the validation succeeded or an error code.
8507 */
8508static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008509xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8510 xmlRelaxNGDefinePtr defines)
8511{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008512 int ret = 0;
8513
8514 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008515 ret = xmlRelaxNGValidateValue(ctxt, defines);
8516 if (ret != 0)
8517 break;
8518 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008519 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008520 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008521}
8522
8523/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008524 * xmlRelaxNGValidateValue:
8525 * @ctxt: a Relax-NG validation context
8526 * @define: the definition to verify
8527 *
8528 * Validate the given definition for the current value
8529 *
8530 * Returns 0 if the validation succeeded or an error code.
8531 */
8532static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008533xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8534 xmlRelaxNGDefinePtr define)
8535{
Daniel Veillardedc91922003-01-26 00:52:04 +00008536 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008537 xmlChar *value;
8538
8539 value = ctxt->state->value;
8540 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008541 case XML_RELAXNG_EMPTY:{
8542 if ((value != NULL) && (value[0] != 0)) {
8543 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008544
William M. Brack76e95df2003-10-18 16:20:14 +00008545 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008546 idx++;
8547 if (value[idx] != 0)
8548 ret = -1;
8549 }
8550 break;
8551 }
8552 case XML_RELAXNG_TEXT:
8553 break;
8554 case XML_RELAXNG_VALUE:{
8555 if (!xmlStrEqual(value, define->value)) {
8556 if (define->name != NULL) {
8557 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008558
Daniel Veillard4c004142003-10-07 11:33:24 +00008559 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8560 if ((lib != NULL) && (lib->comp != NULL)) {
8561 ret = lib->comp(lib->data, define->name,
8562 define->value, define->node,
8563 (void *) define->attrs,
8564 value, ctxt->state->node);
8565 } else
8566 ret = -1;
8567 if (ret < 0) {
8568 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8569 define->name);
8570 return (-1);
8571 } else if (ret == 1) {
8572 ret = 0;
8573 } else {
8574 ret = -1;
8575 }
8576 } else {
8577 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008578
Daniel Veillard4c004142003-10-07 11:33:24 +00008579 /*
8580 * TODO: trivial optimizations are possible by
8581 * computing at compile-time
8582 */
8583 nval = xmlRelaxNGNormalize(ctxt, define->value);
8584 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008585
Daniel Veillard4c004142003-10-07 11:33:24 +00008586 if ((nval == NULL) || (nvalue == NULL) ||
8587 (!xmlStrEqual(nval, nvalue)))
8588 ret = -1;
8589 if (nval != NULL)
8590 xmlFree(nval);
8591 if (nvalue != NULL)
8592 xmlFree(nvalue);
8593 }
8594 }
8595 if (ret == 0)
8596 xmlRelaxNGNextValue(ctxt);
8597 break;
8598 }
8599 case XML_RELAXNG_DATATYPE:{
8600 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8601 ctxt->state->seq);
8602 if (ret == 0)
8603 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008604
Daniel Veillard4c004142003-10-07 11:33:24 +00008605 break;
8606 }
8607 case XML_RELAXNG_CHOICE:{
8608 xmlRelaxNGDefinePtr list = define->content;
8609 xmlChar *oldvalue;
8610
8611 oldflags = ctxt->flags;
8612 ctxt->flags |= FLAGS_IGNORABLE;
8613
8614 oldvalue = ctxt->state->value;
8615 while (list != NULL) {
8616 ret = xmlRelaxNGValidateValue(ctxt, list);
8617 if (ret == 0) {
8618 break;
8619 }
8620 ctxt->state->value = oldvalue;
8621 list = list->next;
8622 }
8623 ctxt->flags = oldflags;
8624 if (ret != 0) {
8625 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8626 xmlRelaxNGDumpValidError(ctxt);
8627 } else {
8628 if (ctxt->errNr > 0)
8629 xmlRelaxNGPopErrors(ctxt, 0);
8630 }
8631 if (ret == 0)
8632 xmlRelaxNGNextValue(ctxt);
8633 break;
8634 }
8635 case XML_RELAXNG_LIST:{
8636 xmlRelaxNGDefinePtr list = define->content;
8637 xmlChar *oldvalue, *oldend, *val, *cur;
8638
Daniel Veillard416589a2003-02-17 17:25:42 +00008639#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008640 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008641#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008642
Daniel Veillard4c004142003-10-07 11:33:24 +00008643 oldvalue = ctxt->state->value;
8644 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008645
Daniel Veillard4c004142003-10-07 11:33:24 +00008646 val = xmlStrdup(oldvalue);
8647 if (val == NULL) {
8648 val = xmlStrdup(BAD_CAST "");
8649 }
8650 if (val == NULL) {
8651 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8652 return (-1);
8653 }
8654 cur = val;
8655 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008656 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008657 *cur = 0;
8658 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008659#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008660 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008661#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008662 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008663 *cur++ = 0;
8664 } else
8665 cur++;
8666 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008667#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008668 xmlGenericError(xmlGenericErrorContext,
8669 "list value: '%s' found %d items\n",
8670 oldvalue, nb_values);
8671 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008672#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008673 ctxt->state->endvalue = cur;
8674 cur = val;
8675 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8676 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008677
Daniel Veillard4c004142003-10-07 11:33:24 +00008678 ctxt->state->value = cur;
8679
8680 while (list != NULL) {
8681 if (ctxt->state->value == ctxt->state->endvalue)
8682 ctxt->state->value = NULL;
8683 ret = xmlRelaxNGValidateValue(ctxt, list);
8684 if (ret != 0) {
8685#ifdef DEBUG_LIST
8686 xmlGenericError(xmlGenericErrorContext,
8687 "Failed to validate value: '%s' with %d rule\n",
8688 ctxt->state->value, nb_values);
8689#endif
8690 break;
8691 }
8692#ifdef DEBUG_LIST
8693 nb_values++;
8694#endif
8695 list = list->next;
8696 }
8697
8698 if ((ret == 0) && (ctxt->state->value != NULL) &&
8699 (ctxt->state->value != ctxt->state->endvalue)) {
8700 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8701 ctxt->state->value);
8702 ret = -1;
8703 }
8704 xmlFree(val);
8705 ctxt->state->value = oldvalue;
8706 ctxt->state->endvalue = oldend;
8707 break;
8708 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008709 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008710 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8711 if (ret != 0) {
8712 break;
8713 }
8714 /* no break on purpose */
8715 case XML_RELAXNG_ZEROORMORE:{
8716 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008717
Daniel Veillard4c004142003-10-07 11:33:24 +00008718 oldflags = ctxt->flags;
8719 ctxt->flags |= FLAGS_IGNORABLE;
8720 cur = ctxt->state->value;
8721 temp = NULL;
8722 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8723 (temp != cur)) {
8724 temp = cur;
8725 ret =
8726 xmlRelaxNGValidateValueList(ctxt, define->content);
8727 if (ret != 0) {
8728 ctxt->state->value = temp;
8729 ret = 0;
8730 break;
8731 }
8732 cur = ctxt->state->value;
8733 }
8734 ctxt->flags = oldflags;
8735 if (ret != 0) {
8736 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8737 xmlRelaxNGDumpValidError(ctxt);
8738 } else {
8739 if (ctxt->errNr > 0)
8740 xmlRelaxNGPopErrors(ctxt, 0);
8741 }
8742 break;
8743 }
8744 case XML_RELAXNG_EXCEPT:{
8745 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +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_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008760 case XML_RELAXNG_GROUP:{
8761 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008762
Daniel Veillard4c004142003-10-07 11:33:24 +00008763 list = define->content;
8764 while (list != NULL) {
8765 ret = xmlRelaxNGValidateValue(ctxt, list);
8766 if (ret != 0) {
8767 ret = -1;
8768 break;
8769 } else
8770 ret = 0;
8771 list = list->next;
8772 }
8773 break;
8774 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008775 case XML_RELAXNG_REF:
8776 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008777 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8778 break;
8779 default:
8780 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008781 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008782 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008783}
8784
8785/**
8786 * xmlRelaxNGValidateValueContent:
8787 * @ctxt: a Relax-NG validation context
8788 * @defines: the list of definitions to verify
8789 *
8790 * Validate the given definitions for the current value
8791 *
8792 * Returns 0 if the validation succeeded or an error code.
8793 */
8794static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008795xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8796 xmlRelaxNGDefinePtr defines)
8797{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008798 int ret = 0;
8799
8800 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008801 ret = xmlRelaxNGValidateValue(ctxt, defines);
8802 if (ret != 0)
8803 break;
8804 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008805 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008806 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008807}
8808
8809/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008810 * xmlRelaxNGAttributeMatch:
8811 * @ctxt: a Relax-NG validation context
8812 * @define: the definition to check
8813 * @prop: the attribute
8814 *
8815 * Check if the attribute matches the definition nameClass
8816 *
8817 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8818 */
8819static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008820xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8821 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8822{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008823 int ret;
8824
8825 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008826 if (!xmlStrEqual(define->name, prop->name))
8827 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008828 }
8829 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008830 if (define->ns[0] == 0) {
8831 if (prop->ns != NULL)
8832 return (0);
8833 } else {
8834 if ((prop->ns == NULL) ||
8835 (!xmlStrEqual(define->ns, prop->ns->href)))
8836 return (0);
8837 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008838 }
8839 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008840 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008841 define = define->nameClass;
8842 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008843 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008844
Daniel Veillard4c004142003-10-07 11:33:24 +00008845 list = define->content;
8846 while (list != NULL) {
8847 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8848 if (ret == 1)
8849 return (0);
8850 if (ret < 0)
8851 return (ret);
8852 list = list->next;
8853 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008854 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008855 TODO}
8856 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008857}
8858
8859/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008860 * xmlRelaxNGValidateAttribute:
8861 * @ctxt: a Relax-NG validation context
8862 * @define: the definition to verify
8863 *
8864 * Validate the given attribute definition for that node
8865 *
8866 * Returns 0 if the validation succeeded or an error code.
8867 */
8868static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008869xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8870 xmlRelaxNGDefinePtr define)
8871{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008872 int ret = 0, i;
8873 xmlChar *value, *oldvalue;
8874 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008875 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008876
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008877 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008878 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008879 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008880 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8881 tmp = ctxt->state->attrs[i];
8882 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8883 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8884 (tmp->ns == NULL)) ||
8885 ((tmp->ns != NULL) &&
8886 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8887 prop = tmp;
8888 break;
8889 }
8890 }
8891 }
8892 if (prop != NULL) {
8893 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8894 oldvalue = ctxt->state->value;
8895 oldseq = ctxt->state->seq;
8896 ctxt->state->seq = (xmlNodePtr) prop;
8897 ctxt->state->value = value;
8898 ctxt->state->endvalue = NULL;
8899 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8900 if (ctxt->state->value != NULL)
8901 value = ctxt->state->value;
8902 if (value != NULL)
8903 xmlFree(value);
8904 ctxt->state->value = oldvalue;
8905 ctxt->state->seq = oldseq;
8906 if (ret == 0) {
8907 /*
8908 * flag the attribute as processed
8909 */
8910 ctxt->state->attrs[i] = NULL;
8911 ctxt->state->nbAttrLeft--;
8912 }
8913 } else {
8914 ret = -1;
8915 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008916#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008917 xmlGenericError(xmlGenericErrorContext,
8918 "xmlRelaxNGValidateAttribute(%s): %d\n",
8919 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008920#endif
8921 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008922 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8923 tmp = ctxt->state->attrs[i];
8924 if ((tmp != NULL) &&
8925 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8926 prop = tmp;
8927 break;
8928 }
8929 }
8930 if (prop != NULL) {
8931 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8932 oldvalue = ctxt->state->value;
8933 oldseq = ctxt->state->seq;
8934 ctxt->state->seq = (xmlNodePtr) prop;
8935 ctxt->state->value = value;
8936 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8937 if (ctxt->state->value != NULL)
8938 value = ctxt->state->value;
8939 if (value != NULL)
8940 xmlFree(value);
8941 ctxt->state->value = oldvalue;
8942 ctxt->state->seq = oldseq;
8943 if (ret == 0) {
8944 /*
8945 * flag the attribute as processed
8946 */
8947 ctxt->state->attrs[i] = NULL;
8948 ctxt->state->nbAttrLeft--;
8949 }
8950 } else {
8951 ret = -1;
8952 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008953#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008954 if (define->ns != NULL) {
8955 xmlGenericError(xmlGenericErrorContext,
8956 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8957 define->ns, ret);
8958 } else {
8959 xmlGenericError(xmlGenericErrorContext,
8960 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8961 ret);
8962 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008963#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008964 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008965
8966 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008967}
8968
8969/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008970 * xmlRelaxNGValidateAttributeList:
8971 * @ctxt: a Relax-NG validation context
8972 * @define: the list of definition to verify
8973 *
8974 * Validate the given node against the list of attribute definitions
8975 *
8976 * Returns 0 if the validation succeeded or an error code.
8977 */
8978static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008979xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8980 xmlRelaxNGDefinePtr defines)
8981{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008982 int ret = 0, res;
8983 int needmore = 0;
8984 xmlRelaxNGDefinePtr cur;
8985
8986 cur = defines;
8987 while (cur != NULL) {
8988 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008989 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8990 ret = -1;
8991 } else
8992 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008993 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008994 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008995 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00008996 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008997 cur = defines;
8998 while (cur != NULL) {
8999 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009000 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9001 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9002 if (res < 0)
9003 ret = -1;
9004 } else {
9005 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9006 return (-1);
9007 }
9008 if (res == -1) /* continues on -2 */
9009 break;
9010 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009011 cur = cur->next;
9012 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009013
9014 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009015}
9016
9017/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009018 * xmlRelaxNGNodeMatchesList:
9019 * @node: the node
9020 * @list: a NULL terminated array of definitions
9021 *
9022 * Check if a node can be matched by one of the definitions
9023 *
9024 * Returns 1 if matches 0 otherwise
9025 */
9026static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009027xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9028{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009029 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009030 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009031
9032 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009033 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009034
9035 cur = list[i++];
9036 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009037 if ((node->type == XML_ELEMENT_NODE) &&
9038 (cur->type == XML_RELAXNG_ELEMENT)) {
9039 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9040 if (tmp == 1)
9041 return (1);
9042 } else if (((node->type == XML_TEXT_NODE) ||
9043 (node->type == XML_CDATA_SECTION_NODE)) &&
9044 (cur->type == XML_RELAXNG_TEXT)) {
9045 return (1);
9046 }
9047 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009048 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009049 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009050}
9051
9052/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009053 * xmlRelaxNGValidateInterleave:
9054 * @ctxt: a Relax-NG validation context
9055 * @define: the definition to verify
9056 *
9057 * Validate an interleave definition for a node.
9058 *
9059 * Returns 0 if the validation succeeded or an error code.
9060 */
9061static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009062xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9063 xmlRelaxNGDefinePtr define)
9064{
William M. Brack779af002003-08-01 15:55:39 +00009065 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009066 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009067 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009068
9069 xmlRelaxNGValidStatePtr oldstate;
9070 xmlRelaxNGPartitionPtr partitions;
9071 xmlRelaxNGInterleaveGroupPtr group = NULL;
9072 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9073 xmlNodePtr *list = NULL, *lasts = NULL;
9074
9075 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009076 partitions = (xmlRelaxNGPartitionPtr) define->data;
9077 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009078 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009079 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9080 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009081 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009082 /*
9083 * Optimizations for MIXED
9084 */
9085 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009086 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009087 ctxt->flags |= FLAGS_MIXED_CONTENT;
9088 if (nbgroups == 2) {
9089 /*
9090 * this is a pure <mixed> case
9091 */
9092 if (ctxt->state != NULL)
9093 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9094 ctxt->state->seq);
9095 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9096 ret = xmlRelaxNGValidateDefinition(ctxt,
9097 partitions->groups[1]->
9098 rule);
9099 else
9100 ret = xmlRelaxNGValidateDefinition(ctxt,
9101 partitions->groups[0]->
9102 rule);
9103 if (ret == 0) {
9104 if (ctxt->state != NULL)
9105 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9106 ctxt->state->
9107 seq);
9108 }
9109 ctxt->flags = oldflags;
9110 return (ret);
9111 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009112 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009113
9114 /*
9115 * Build arrays to store the first and last node of the chain
9116 * pertaining to each group
9117 */
9118 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9119 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009120 xmlRngVErrMemory(ctxt, "validating\n");
9121 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009122 }
9123 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9124 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9125 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009126 xmlRngVErrMemory(ctxt, "validating\n");
9127 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009128 }
9129 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9130
9131 /*
9132 * Walk the sequence of children finding the right group and
9133 * sorting them in sequences.
9134 */
9135 cur = ctxt->state->seq;
9136 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9137 start = cur;
9138 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009139 ctxt->state->seq = cur;
9140 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009141 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009142 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009143
Daniel Veillard4c004142003-10-07 11:33:24 +00009144 if ((cur->type == XML_TEXT_NODE) ||
9145 (cur->type == XML_CDATA_SECTION_NODE)) {
9146 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9147 NULL);
9148 } else if (cur->type == XML_ELEMENT_NODE) {
9149 if (cur->ns != NULL) {
9150 tmp = xmlHashLookup2(partitions->triage, cur->name,
9151 cur->ns->href);
9152 if (tmp == NULL)
9153 tmp = xmlHashLookup2(partitions->triage,
9154 BAD_CAST "#any",
9155 cur->ns->href);
9156 } else
9157 tmp =
9158 xmlHashLookup2(partitions->triage, cur->name,
9159 NULL);
9160 if (tmp == NULL)
9161 tmp =
9162 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9163 NULL);
9164 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009165
Daniel Veillard4c004142003-10-07 11:33:24 +00009166 if (tmp == NULL) {
9167 i = nbgroups;
9168 } else {
9169 i = ((long) tmp) - 1;
9170 if (partitions->flags & IS_NEEDCHECK) {
9171 group = partitions->groups[i];
9172 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9173 i = nbgroups;
9174 }
9175 }
9176 } else {
9177 for (i = 0; i < nbgroups; i++) {
9178 group = partitions->groups[i];
9179 if (group == NULL)
9180 continue;
9181 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9182 break;
9183 }
9184 }
9185 /*
9186 * We break as soon as an element not matched is found
9187 */
9188 if (i >= nbgroups) {
9189 break;
9190 }
9191 if (lasts[i] != NULL) {
9192 lasts[i]->next = cur;
9193 lasts[i] = cur;
9194 } else {
9195 list[i] = cur;
9196 lasts[i] = cur;
9197 }
9198 if (cur->next != NULL)
9199 lastchg = cur->next;
9200 else
9201 lastchg = cur;
9202 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009203 }
9204 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009205 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9206 ret = -1;
9207 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009208 }
9209 lastelem = cur;
9210 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009211 for (i = 0; i < nbgroups; i++) {
9212 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9213 group = partitions->groups[i];
9214 if (lasts[i] != NULL) {
9215 last = lasts[i]->next;
9216 lasts[i]->next = NULL;
9217 }
9218 ctxt->state->seq = list[i];
9219 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9220 if (ret != 0)
9221 break;
9222 if (ctxt->state != NULL) {
9223 cur = ctxt->state->seq;
9224 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9225 xmlRelaxNGFreeValidState(ctxt, oldstate);
9226 oldstate = ctxt->state;
9227 ctxt->state = NULL;
9228 if (cur != NULL) {
9229 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9230 ret = -1;
9231 ctxt->state = oldstate;
9232 goto done;
9233 }
9234 } else if (ctxt->states != NULL) {
9235 int j;
9236 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009237
Daniel Veillard4c004142003-10-07 11:33:24 +00009238 for (j = 0; j < ctxt->states->nbState; j++) {
9239 cur = ctxt->states->tabState[j]->seq;
9240 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9241 if (cur == NULL) {
9242 found = 1;
9243 break;
9244 }
9245 }
9246 if (ctxt->states->nbState > 0) {
9247 xmlRelaxNGFreeValidState(ctxt, oldstate);
9248 oldstate =
9249 ctxt->states->tabState[ctxt->states->nbState - 1];
9250 }
9251 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9252 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9253 }
9254 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9255 ctxt->states = NULL;
9256 if (found == 0) {
9257 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9258 ret = -1;
9259 ctxt->state = oldstate;
9260 goto done;
9261 }
9262 } else {
9263 ret = -1;
9264 break;
9265 }
9266 if (lasts[i] != NULL) {
9267 lasts[i]->next = last;
9268 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009269 }
9270 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009271 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009272 ctxt->state = oldstate;
9273 ctxt->state->seq = lastelem;
9274 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009275 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9276 ret = -1;
9277 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009278 }
9279
Daniel Veillard4c004142003-10-07 11:33:24 +00009280 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009281 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009282 /*
9283 * builds the next links chain from the prev one
9284 */
9285 cur = lastchg;
9286 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009287 if ((cur == start) || (cur->prev == NULL))
9288 break;
9289 cur->prev->next = cur;
9290 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009291 }
9292 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009293 if (ctxt->errNr > errNr)
9294 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009295 }
9296
9297 xmlFree(list);
9298 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009299 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009300}
9301
9302/**
9303 * xmlRelaxNGValidateDefinitionList:
9304 * @ctxt: a Relax-NG validation context
9305 * @define: the list of definition to verify
9306 *
9307 * Validate the given node content against the (list) of definitions
9308 *
9309 * Returns 0 if the validation succeeded or an error code.
9310 */
9311static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009312xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9313 xmlRelaxNGDefinePtr defines)
9314{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009315 int ret = 0, res;
9316
9317
Daniel Veillard952379b2003-03-17 15:37:12 +00009318 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009319 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9320 BAD_CAST "NULL definition list");
9321 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009322 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009323 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009324 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9325 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9326 if (res < 0)
9327 ret = -1;
9328 } else {
9329 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9330 return (-1);
9331 }
9332 if (res == -1) /* continues on -2 */
9333 break;
9334 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009335 }
9336
Daniel Veillard4c004142003-10-07 11:33:24 +00009337 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009338}
9339
9340/**
9341 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009342 * @ctxt: a Relax-NG validation context
9343 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009344 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009345 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009346 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009347 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009348 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009349 */
9350static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009351xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9352 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9353{
Daniel Veillard580ced82003-03-21 21:22:48 +00009354 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009355
Daniel Veillardfd573f12003-03-16 17:52:32 +00009356 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009357 if (!xmlStrEqual(elem->name, define->name)) {
9358 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9359 return (0);
9360 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009361 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009362 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009363 if (elem->ns == NULL) {
9364 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9365 return (0);
9366 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9367 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9368 elem->name, define->ns);
9369 return (0);
9370 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009371 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009372 (define->name == NULL)) {
9373 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9374 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009375 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009376 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9377 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009378 }
9379
9380 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009381 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009382
9383 define = define->nameClass;
9384 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009385 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009386
Daniel Veillard4c004142003-10-07 11:33:24 +00009387 if (ctxt != NULL) {
9388 oldflags = ctxt->flags;
9389 ctxt->flags |= FLAGS_IGNORABLE;
9390 }
9391
9392 list = define->content;
9393 while (list != NULL) {
9394 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9395 if (ret == 1) {
9396 if (ctxt != NULL)
9397 ctxt->flags = oldflags;
9398 return (0);
9399 }
9400 if (ret < 0) {
9401 if (ctxt != NULL)
9402 ctxt->flags = oldflags;
9403 return (ret);
9404 }
9405 list = list->next;
9406 }
9407 ret = 1;
9408 if (ctxt != NULL) {
9409 ctxt->flags = oldflags;
9410 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009411 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009412 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009413
Daniel Veillard4c004142003-10-07 11:33:24 +00009414 if (ctxt != NULL) {
9415 oldflags = ctxt->flags;
9416 ctxt->flags |= FLAGS_IGNORABLE;
9417 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009418
Daniel Veillard4c004142003-10-07 11:33:24 +00009419 list = define->nameClass;
9420 while (list != NULL) {
9421 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9422 if (ret == 1) {
9423 if (ctxt != NULL)
9424 ctxt->flags = oldflags;
9425 return (1);
9426 }
9427 if (ret < 0) {
9428 if (ctxt != NULL)
9429 ctxt->flags = oldflags;
9430 return (ret);
9431 }
9432 list = list->next;
9433 }
9434 if (ctxt != NULL) {
9435 if (ret != 0) {
9436 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9437 xmlRelaxNGDumpValidError(ctxt);
9438 } else {
9439 if (ctxt->errNr > 0)
9440 xmlRelaxNGPopErrors(ctxt, 0);
9441 }
9442 }
9443 ret = 0;
9444 if (ctxt != NULL) {
9445 ctxt->flags = oldflags;
9446 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009447 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009448 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009449 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009450 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009451}
9452
9453/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009454 * xmlRelaxNGBestState:
9455 * @ctxt: a Relax-NG validation context
9456 *
9457 * Find the "best" state in the ctxt->states list of states to report
9458 * errors about. I.e. a state with no element left in the child list
9459 * or the one with the less attributes left.
9460 * This is called only if a falidation error was detected
9461 *
9462 * Returns the index of the "best" state or -1 in case of error
9463 */
9464static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009465xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9466{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009467 xmlRelaxNGValidStatePtr state;
9468 int i, tmp;
9469 int best = -1;
9470 int value = 1000000;
9471
9472 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9473 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009474 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009475
Daniel Veillard4c004142003-10-07 11:33:24 +00009476 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009477 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009478 if (state == NULL)
9479 continue;
9480 if (state->seq != NULL) {
9481 if ((best == -1) || (value > 100000)) {
9482 value = 100000;
9483 best = i;
9484 }
9485 } else {
9486 tmp = state->nbAttrLeft;
9487 if ((best == -1) || (value > tmp)) {
9488 value = tmp;
9489 best = i;
9490 }
9491 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009492 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009493 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009494}
9495
9496/**
9497 * xmlRelaxNGLogBestError:
9498 * @ctxt: a Relax-NG validation context
9499 *
9500 * Find the "best" state in the ctxt->states list of states to report
9501 * errors about and log it.
9502 */
9503static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009504xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9505{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009506 int best;
9507
9508 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9509 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009510 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009511
9512 best = xmlRelaxNGBestState(ctxt);
9513 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009514 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009515
Daniel Veillard4c004142003-10-07 11:33:24 +00009516 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009517 }
9518}
9519
9520/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009521 * xmlRelaxNGValidateElementEnd:
9522 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009523 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009524 *
9525 * Validate the end of the element, implements check that
9526 * there is nothing left not consumed in the element content
9527 * or in the attribute list.
9528 *
9529 * Returns 0 if the validation succeeded or an error code.
9530 */
9531static int
William M. Brack272693c2003-11-14 16:20:34 +00009532xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009533{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009534 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009535 xmlRelaxNGValidStatePtr state;
9536
9537 state = ctxt->state;
9538 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009539 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9540 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009541 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009542 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9543 state->node->name, state->seq->name);
9544 }
9545 return (-1);
9546 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009547 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009548 for (i = 0; i < state->nbAttrs; i++) {
9549 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009550 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009551 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9552 state->attrs[i]->name, state->node->name);
9553 }
9554 return (-1 - i);
9555 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009556 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009557 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009558}
9559
9560/**
9561 * xmlRelaxNGValidateState:
9562 * @ctxt: a Relax-NG validation context
9563 * @define: the definition to verify
9564 *
9565 * Validate the current state against the definition
9566 *
9567 * Returns 0 if the validation succeeded or an error code.
9568 */
9569static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009570xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9571 xmlRelaxNGDefinePtr define)
9572{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009573 xmlNodePtr node;
9574 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009575 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009576
9577 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009578 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9579 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009580 }
9581
9582 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009583 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009584 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009585 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009586 }
9587#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009588 for (i = 0; i < ctxt->depth; i++)
9589 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009590 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009591 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009592 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009593 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009594 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009595 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009596 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009597 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009598#endif
9599 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009600 switch (define->type) {
9601 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009602 node = xmlRelaxNGSkipIgnored(ctxt, node);
9603 ret = 0;
9604 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009605 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009606 ret = -1;
9607 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009608 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009609 while ((node != NULL) &&
9610 ((node->type == XML_TEXT_NODE) ||
9611 (node->type == XML_COMMENT_NODE) ||
9612 (node->type == XML_PI_NODE) ||
9613 (node->type == XML_CDATA_SECTION_NODE)))
9614 node = node->next;
9615 ctxt->state->seq = node;
9616 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009617 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009618 errNr = ctxt->errNr;
9619 node = xmlRelaxNGSkipIgnored(ctxt, node);
9620 if (node == NULL) {
9621 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9622 ret = -1;
9623 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9624 xmlRelaxNGDumpValidError(ctxt);
9625 break;
9626 }
9627 if (node->type != XML_ELEMENT_NODE) {
9628 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9629 ret = -1;
9630 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9631 xmlRelaxNGDumpValidError(ctxt);
9632 break;
9633 }
9634 /*
9635 * This node was already validated successfully against
9636 * this definition.
9637 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009638 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009639 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9640 if (ctxt->errNr > errNr)
9641 xmlRelaxNGPopErrors(ctxt, errNr);
9642 if (ctxt->errNr != 0) {
9643 while ((ctxt->err != NULL) &&
9644 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9645 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9646 ||
9647 ((ctxt->err->err ==
9648 XML_RELAXNG_ERR_ELEMEXTRANS)
9649 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9650 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9651 || (ctxt->err->err ==
9652 XML_RELAXNG_ERR_NOTELEM)))
9653 xmlRelaxNGValidErrorPop(ctxt);
9654 }
9655 break;
9656 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009657
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009658 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9659 if (ret <= 0) {
9660 ret = -1;
9661 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9662 xmlRelaxNGDumpValidError(ctxt);
9663 break;
9664 }
9665 ret = 0;
9666 if (ctxt->errNr != 0) {
9667 if (ctxt->errNr > errNr)
9668 xmlRelaxNGPopErrors(ctxt, errNr);
9669 while ((ctxt->err != NULL) &&
9670 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9671 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9672 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9673 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9674 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9675 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9676 xmlRelaxNGValidErrorPop(ctxt);
9677 }
9678 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009679
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009680 oldflags = ctxt->flags;
9681 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9682 ctxt->flags -= FLAGS_MIXED_CONTENT;
9683 }
9684 state = xmlRelaxNGNewValidState(ctxt, node);
9685 if (state == NULL) {
9686 ret = -1;
9687 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9688 xmlRelaxNGDumpValidError(ctxt);
9689 break;
9690 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009691
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009692 oldstate = ctxt->state;
9693 ctxt->state = state;
9694 if (define->attrs != NULL) {
9695 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9696 if (tmp != 0) {
9697 ret = -1;
9698 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9699 }
9700 }
9701 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009702 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9703 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9704 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009705
Daniel Veillard4c004142003-10-07 11:33:24 +00009706 nstate = xmlRelaxNGNewValidState(ctxt, node);
9707 ctxt->state = nstate;
9708 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009709
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009710 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9711 define->contModel,
9712 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009713 nseq = ctxt->state->seq;
9714 ctxt->state = tmpstate;
9715 ctxt->states = tmpstates;
9716 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009717
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009718#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009719 xmlGenericError(xmlGenericErrorContext,
9720 "Validating content of '%s' : %d\n",
9721 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009722#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009723 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009724 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009725
9726 if (ctxt->states != NULL) {
9727 tmp = -1;
9728
Daniel Veillardce192eb2003-04-16 15:58:05 +00009729 for (i = 0; i < ctxt->states->nbState; i++) {
9730 state = ctxt->states->tabState[i];
9731 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009732 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009733
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009734 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009735 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009736 break;
9737 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009738 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009739 if (tmp != 0) {
9740 /*
9741 * validation error, log the message for the "best" one
9742 */
9743 ctxt->flags |= FLAGS_IGNORABLE;
9744 xmlRelaxNGLogBestError(ctxt);
9745 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009746 for (i = 0; i < ctxt->states->nbState; i++) {
9747 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009748 ctxt->states->
9749 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009750 }
9751 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9752 ctxt->flags = oldflags;
9753 ctxt->states = NULL;
9754 if ((ret == 0) && (tmp == -1))
9755 ret = -1;
9756 } else {
9757 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009758 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009759 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009760 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009761 xmlRelaxNGFreeValidState(ctxt, state);
9762 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009763 } else {
9764 if (define->content != NULL) {
9765 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009766 define->
9767 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009768 if (tmp != 0) {
9769 ret = -1;
9770 if (ctxt->state == NULL) {
9771 ctxt->state = oldstate;
9772 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9773 node->name);
9774 ctxt->state = NULL;
9775 } else {
9776 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9777 node->name);
9778 }
9779
9780 }
9781 }
9782 if (ctxt->states != NULL) {
9783 tmp = -1;
9784
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009785 for (i = 0; i < ctxt->states->nbState; i++) {
9786 state = ctxt->states->tabState[i];
9787 ctxt->state = state;
9788
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009789 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009790 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009791 break;
9792 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009793 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009794 if (tmp != 0) {
9795 /*
9796 * validation error, log the message for the "best" one
9797 */
9798 ctxt->flags |= FLAGS_IGNORABLE;
9799 xmlRelaxNGLogBestError(ctxt);
9800 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009801 for (i = 0; i < ctxt->states->nbState; i++) {
9802 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009803 ctxt->states->
9804 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009805 }
9806 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9807 ctxt->flags = oldflags;
9808 ctxt->states = NULL;
9809 if ((ret == 0) && (tmp == -1))
9810 ret = -1;
9811 } else {
9812 state = ctxt->state;
9813 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009814 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009815 xmlRelaxNGFreeValidState(ctxt, state);
9816 }
9817 }
9818 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009819 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009820 }
9821 ctxt->flags = oldflags;
9822 ctxt->state = oldstate;
9823 if (oldstate != NULL)
9824 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9825 if (ret != 0) {
9826 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9827 xmlRelaxNGDumpValidError(ctxt);
9828 ret = 0;
9829 } else {
9830 ret = -2;
9831 }
9832 } else {
9833 if (ctxt->errNr > errNr)
9834 xmlRelaxNGPopErrors(ctxt, errNr);
9835 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009836
9837#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009838 xmlGenericError(xmlGenericErrorContext,
9839 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9840 node->name, ret);
9841 if (oldstate == NULL)
9842 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9843 else if (oldstate->seq == NULL)
9844 xmlGenericError(xmlGenericErrorContext, ": done\n");
9845 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9846 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9847 oldstate->seq->name);
9848 else
9849 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9850 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009851#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009852 break;
9853 case XML_RELAXNG_OPTIONAL:{
9854 errNr = ctxt->errNr;
9855 oldflags = ctxt->flags;
9856 ctxt->flags |= FLAGS_IGNORABLE;
9857 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9858 ret =
9859 xmlRelaxNGValidateDefinitionList(ctxt,
9860 define->content);
9861 if (ret != 0) {
9862 if (ctxt->state != NULL)
9863 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9864 ctxt->state = oldstate;
9865 ctxt->flags = oldflags;
9866 ret = 0;
9867 if (ctxt->errNr > errNr)
9868 xmlRelaxNGPopErrors(ctxt, errNr);
9869 break;
9870 }
9871 if (ctxt->states != NULL) {
9872 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9873 } else {
9874 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9875 if (ctxt->states == NULL) {
9876 xmlRelaxNGFreeValidState(ctxt, oldstate);
9877 ctxt->flags = oldflags;
9878 ret = -1;
9879 if (ctxt->errNr > errNr)
9880 xmlRelaxNGPopErrors(ctxt, errNr);
9881 break;
9882 }
9883 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9884 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9885 ctxt->state = NULL;
9886 }
9887 ctxt->flags = oldflags;
9888 ret = 0;
9889 if (ctxt->errNr > errNr)
9890 xmlRelaxNGPopErrors(ctxt, errNr);
9891 break;
9892 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009893 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009894 errNr = ctxt->errNr;
9895 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9896 if (ret != 0) {
9897 break;
9898 }
9899 if (ctxt->errNr > errNr)
9900 xmlRelaxNGPopErrors(ctxt, errNr);
9901 /* no break on purpose */
9902 case XML_RELAXNG_ZEROORMORE:{
9903 int progress;
9904 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9905 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009906
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009907 errNr = ctxt->errNr;
9908 res = xmlRelaxNGNewStates(ctxt, 1);
9909 if (res == NULL) {
9910 ret = -1;
9911 break;
9912 }
9913 /*
9914 * All the input states are also exit states
9915 */
9916 if (ctxt->state != NULL) {
9917 xmlRelaxNGAddStates(ctxt, res,
9918 xmlRelaxNGCopyValidState(ctxt,
9919 ctxt->
9920 state));
9921 } else {
9922 for (j = 0; j < ctxt->states->nbState; j++) {
9923 xmlRelaxNGAddStates(ctxt, res,
9924 xmlRelaxNGCopyValidState(ctxt,
9925 ctxt->
9926 states->
9927 tabState
9928 [j]));
9929 }
9930 }
9931 oldflags = ctxt->flags;
9932 ctxt->flags |= FLAGS_IGNORABLE;
9933 do {
9934 progress = 0;
9935 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009936
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009937 if (ctxt->states != NULL) {
9938 states = ctxt->states;
9939 for (i = 0; i < states->nbState; i++) {
9940 ctxt->state = states->tabState[i];
9941 ctxt->states = NULL;
9942 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9943 define->
9944 content);
9945 if (ret == 0) {
9946 if (ctxt->state != NULL) {
9947 tmp = xmlRelaxNGAddStates(ctxt, res,
9948 ctxt->state);
9949 ctxt->state = NULL;
9950 if (tmp == 1)
9951 progress = 1;
9952 } else if (ctxt->states != NULL) {
9953 for (j = 0; j < ctxt->states->nbState;
9954 j++) {
9955 tmp =
9956 xmlRelaxNGAddStates(ctxt, res,
9957 ctxt->
9958 states->
9959 tabState
9960 [j]);
9961 if (tmp == 1)
9962 progress = 1;
9963 }
9964 xmlRelaxNGFreeStates(ctxt,
9965 ctxt->states);
9966 ctxt->states = NULL;
9967 }
9968 } else {
9969 if (ctxt->state != NULL) {
9970 xmlRelaxNGFreeValidState(ctxt,
9971 ctxt->state);
9972 ctxt->state = NULL;
9973 }
9974 }
9975 }
9976 } else {
9977 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9978 define->
9979 content);
9980 if (ret != 0) {
9981 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9982 ctxt->state = NULL;
9983 } else {
9984 base = res->nbState;
9985 if (ctxt->state != NULL) {
9986 tmp = xmlRelaxNGAddStates(ctxt, res,
9987 ctxt->state);
9988 ctxt->state = NULL;
9989 if (tmp == 1)
9990 progress = 1;
9991 } else if (ctxt->states != NULL) {
9992 for (j = 0; j < ctxt->states->nbState; j++) {
9993 tmp = xmlRelaxNGAddStates(ctxt, res,
9994 ctxt->
9995 states->
9996 tabState[j]);
9997 if (tmp == 1)
9998 progress = 1;
9999 }
10000 if (states == NULL) {
10001 states = ctxt->states;
10002 } else {
10003 xmlRelaxNGFreeStates(ctxt,
10004 ctxt->states);
10005 }
10006 ctxt->states = NULL;
10007 }
10008 }
10009 }
10010 if (progress) {
10011 /*
10012 * Collect all the new nodes added at that step
10013 * and make them the new node set
10014 */
10015 if (res->nbState - base == 1) {
10016 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10017 res->
10018 tabState
10019 [base]);
10020 } else {
10021 if (states == NULL) {
10022 xmlRelaxNGNewStates(ctxt,
10023 res->nbState - base);
10024 }
10025 states->nbState = 0;
10026 for (i = base; i < res->nbState; i++)
10027 xmlRelaxNGAddStates(ctxt, states,
10028 xmlRelaxNGCopyValidState
10029 (ctxt,
10030 res->tabState[i]));
10031 ctxt->states = states;
10032 }
10033 }
10034 } while (progress == 1);
10035 if (states != NULL) {
10036 xmlRelaxNGFreeStates(ctxt, states);
10037 }
10038 ctxt->states = res;
10039 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010040#if 0
10041 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010042 * errors may have to be propagated back...
10043 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010044 if (ctxt->errNr > errNr)
10045 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010046#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010047 ret = 0;
10048 break;
10049 }
10050 case XML_RELAXNG_CHOICE:{
10051 xmlRelaxNGDefinePtr list = NULL;
10052 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010053
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010054 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010055
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010056 errNr = ctxt->errNr;
Daniel Veillard9186a1f2005-01-15 12:38:10 +000010057 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10058 (node != NULL)) {
10059 /*
10060 * node == NULL can't be optimized since IS_TRIABLE
10061 * doesn't account for choice which may lead to
10062 * only attributes.
10063 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010064 xmlHashTablePtr triage =
10065 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010066
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010067 /*
10068 * Something we can optimize cleanly there is only one
10069 * possble branch out !
10070 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010071 if ((node->type == XML_TEXT_NODE) ||
10072 (node->type == XML_CDATA_SECTION_NODE)) {
10073 list =
10074 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10075 } else if (node->type == XML_ELEMENT_NODE) {
10076 if (node->ns != NULL) {
10077 list = xmlHashLookup2(triage, node->name,
10078 node->ns->href);
10079 if (list == NULL)
10080 list =
10081 xmlHashLookup2(triage, BAD_CAST "#any",
10082 node->ns->href);
10083 } else
10084 list =
10085 xmlHashLookup2(triage, node->name, NULL);
10086 if (list == NULL)
10087 list =
10088 xmlHashLookup2(triage, BAD_CAST "#any",
10089 NULL);
10090 }
10091 if (list == NULL) {
10092 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010093 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010094 break;
10095 }
10096 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10097 if (ret == 0) {
10098 }
10099 break;
10100 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010101
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010102 list = define->content;
10103 oldflags = ctxt->flags;
10104 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010105
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010106 while (list != NULL) {
10107 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10108 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10109 if (ret == 0) {
10110 if (states == NULL) {
10111 states = xmlRelaxNGNewStates(ctxt, 1);
10112 }
10113 if (ctxt->state != NULL) {
10114 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10115 } else if (ctxt->states != NULL) {
10116 for (i = 0; i < ctxt->states->nbState; i++) {
10117 xmlRelaxNGAddStates(ctxt, states,
10118 ctxt->states->
10119 tabState[i]);
10120 }
10121 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10122 ctxt->states = NULL;
10123 }
10124 } else {
10125 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10126 }
10127 ctxt->state = oldstate;
10128 list = list->next;
10129 }
10130 if (states != NULL) {
10131 xmlRelaxNGFreeValidState(ctxt, oldstate);
10132 ctxt->states = states;
10133 ctxt->state = NULL;
10134 ret = 0;
10135 } else {
10136 ctxt->states = NULL;
10137 }
10138 ctxt->flags = oldflags;
10139 if (ret != 0) {
10140 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10141 xmlRelaxNGDumpValidError(ctxt);
10142 }
10143 } else {
10144 if (ctxt->errNr > errNr)
10145 xmlRelaxNGPopErrors(ctxt, errNr);
10146 }
10147 break;
10148 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010149 case XML_RELAXNG_DEF:
10150 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010151 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10152 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010153 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010154 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10155 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010156 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010157 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10158 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010159 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010160 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010161 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010162 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010163 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010164 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10165 break;
10166 case XML_RELAXNG_DATATYPE:{
10167 xmlNodePtr child;
10168 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010169
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010170 child = node;
10171 while (child != NULL) {
10172 if (child->type == XML_ELEMENT_NODE) {
10173 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10174 node->parent->name);
10175 ret = -1;
10176 break;
10177 } else if ((child->type == XML_TEXT_NODE) ||
10178 (child->type == XML_CDATA_SECTION_NODE)) {
10179 content = xmlStrcat(content, child->content);
10180 }
10181 /* TODO: handle entities ... */
10182 child = child->next;
10183 }
10184 if (ret == -1) {
10185 if (content != NULL)
10186 xmlFree(content);
10187 break;
10188 }
10189 if (content == NULL) {
10190 content = xmlStrdup(BAD_CAST "");
10191 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010192 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010193 ret = -1;
10194 break;
10195 }
10196 }
10197 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10198 ctxt->state->seq);
10199 if (ret == -1) {
10200 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10201 } else if (ret == 0) {
10202 ctxt->state->seq = NULL;
10203 }
10204 if (content != NULL)
10205 xmlFree(content);
10206 break;
10207 }
10208 case XML_RELAXNG_VALUE:{
10209 xmlChar *content = NULL;
10210 xmlChar *oldvalue;
10211 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010212
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010213 child = node;
10214 while (child != NULL) {
10215 if (child->type == XML_ELEMENT_NODE) {
10216 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10217 node->parent->name);
10218 ret = -1;
10219 break;
10220 } else if ((child->type == XML_TEXT_NODE) ||
10221 (child->type == XML_CDATA_SECTION_NODE)) {
10222 content = xmlStrcat(content, child->content);
10223 }
10224 /* TODO: handle entities ... */
10225 child = child->next;
10226 }
10227 if (ret == -1) {
10228 if (content != NULL)
10229 xmlFree(content);
10230 break;
10231 }
10232 if (content == NULL) {
10233 content = xmlStrdup(BAD_CAST "");
10234 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010235 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010236 ret = -1;
10237 break;
10238 }
10239 }
10240 oldvalue = ctxt->state->value;
10241 ctxt->state->value = content;
10242 ret = xmlRelaxNGValidateValue(ctxt, define);
10243 ctxt->state->value = oldvalue;
10244 if (ret == -1) {
10245 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10246 } else if (ret == 0) {
10247 ctxt->state->seq = NULL;
10248 }
10249 if (content != NULL)
10250 xmlFree(content);
10251 break;
10252 }
10253 case XML_RELAXNG_LIST:{
10254 xmlChar *content;
10255 xmlNodePtr child;
10256 xmlChar *oldvalue, *oldendvalue;
10257 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010258
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010259 /*
10260 * Make sure it's only text nodes
10261 */
10262
10263 content = NULL;
10264 child = node;
10265 while (child != NULL) {
10266 if (child->type == XML_ELEMENT_NODE) {
10267 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10268 node->parent->name);
10269 ret = -1;
10270 break;
10271 } else if ((child->type == XML_TEXT_NODE) ||
10272 (child->type == XML_CDATA_SECTION_NODE)) {
10273 content = xmlStrcat(content, child->content);
10274 }
10275 /* TODO: handle entities ... */
10276 child = child->next;
10277 }
10278 if (ret == -1) {
10279 if (content != NULL)
10280 xmlFree(content);
10281 break;
10282 }
10283 if (content == NULL) {
10284 content = xmlStrdup(BAD_CAST "");
10285 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010286 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010287 ret = -1;
10288 break;
10289 }
10290 }
10291 len = xmlStrlen(content);
10292 oldvalue = ctxt->state->value;
10293 oldendvalue = ctxt->state->endvalue;
10294 ctxt->state->value = content;
10295 ctxt->state->endvalue = content + len;
10296 ret = xmlRelaxNGValidateValue(ctxt, define);
10297 ctxt->state->value = oldvalue;
10298 ctxt->state->endvalue = oldendvalue;
10299 if (ret == -1) {
10300 VALID_ERR(XML_RELAXNG_ERR_LIST);
10301 } else if ((ret == 0) && (node != NULL)) {
10302 ctxt->state->seq = node->next;
10303 }
10304 if (content != NULL)
10305 xmlFree(content);
10306 break;
10307 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010308 case XML_RELAXNG_EXCEPT:
10309 case XML_RELAXNG_PARAM:
10310 TODO ret = -1;
10311 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010312 }
10313 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010314#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010315 for (i = 0; i < ctxt->depth; i++)
10316 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010317 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010318 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010319 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010320 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010321 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010322 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010323 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010324 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010325#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010326 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010327}
10328
10329/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010330 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010331 * @ctxt: a Relax-NG validation context
10332 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010333 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010334 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010335 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010336 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010337 */
10338static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010339xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10340 xmlRelaxNGDefinePtr define)
10341{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010342 xmlRelaxNGStatesPtr states, res;
10343 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010344
Daniel Veillardfd573f12003-03-16 17:52:32 +000010345 /*
10346 * We should NOT have both ctxt->state and ctxt->states
10347 */
10348 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010349 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10350 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010351 }
10352
10353 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010354 if (ctxt->states != NULL) {
10355 ctxt->state = ctxt->states->tabState[0];
10356 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10357 ctxt->states = NULL;
10358 }
10359 ret = xmlRelaxNGValidateState(ctxt, define);
10360 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10361 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10362 ctxt->state = NULL;
10363 }
10364 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10365 ctxt->state = ctxt->states->tabState[0];
10366 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10367 ctxt->states = NULL;
10368 }
10369 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010370 }
10371
10372 states = ctxt->states;
10373 ctxt->states = NULL;
10374 res = NULL;
10375 j = 0;
10376 oldflags = ctxt->flags;
10377 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010378 for (i = 0; i < states->nbState; i++) {
10379 ctxt->state = states->tabState[i];
10380 ctxt->states = NULL;
10381 ret = xmlRelaxNGValidateState(ctxt, define);
10382 /*
10383 * We should NOT have both ctxt->state and ctxt->states
10384 */
10385 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10386 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10387 ctxt->state = NULL;
10388 }
10389 if (ret == 0) {
10390 if (ctxt->states == NULL) {
10391 if (res != NULL) {
10392 /* add the state to the container */
10393 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10394 ctxt->state = NULL;
10395 } else {
10396 /* add the state directly in states */
10397 states->tabState[j++] = ctxt->state;
10398 ctxt->state = NULL;
10399 }
10400 } else {
10401 if (res == NULL) {
10402 /* make it the new container and copy other results */
10403 res = ctxt->states;
10404 ctxt->states = NULL;
10405 for (k = 0; k < j; k++)
10406 xmlRelaxNGAddStates(ctxt, res,
10407 states->tabState[k]);
10408 } else {
10409 /* add all the new results to res and reff the container */
10410 for (k = 0; k < ctxt->states->nbState; k++)
10411 xmlRelaxNGAddStates(ctxt, res,
10412 ctxt->states->tabState[k]);
10413 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10414 ctxt->states = NULL;
10415 }
10416 }
10417 } else {
10418 if (ctxt->state != NULL) {
10419 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10420 ctxt->state = NULL;
10421 } else if (ctxt->states != NULL) {
10422 for (k = 0; k < ctxt->states->nbState; k++)
10423 xmlRelaxNGFreeValidState(ctxt,
10424 ctxt->states->tabState[k]);
10425 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10426 ctxt->states = NULL;
10427 }
10428 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010429 }
10430 ctxt->flags = oldflags;
10431 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010432 xmlRelaxNGFreeStates(ctxt, states);
10433 ctxt->states = res;
10434 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010435 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010436 states->nbState = j;
10437 ctxt->states = states;
10438 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010439 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010440 ctxt->state = states->tabState[0];
10441 xmlRelaxNGFreeStates(ctxt, states);
10442 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010443 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010444 ret = -1;
10445 xmlRelaxNGFreeStates(ctxt, states);
10446 if (ctxt->states != NULL) {
10447 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10448 ctxt->states = NULL;
10449 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010450 }
10451 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010452 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10453 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010454 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010455 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010456}
10457
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010458/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010459 * xmlRelaxNGValidateDocument:
10460 * @ctxt: a Relax-NG validation context
10461 * @doc: the document
10462 *
10463 * Validate the given document
10464 *
10465 * Returns 0 if the validation succeeded or an error code.
10466 */
10467static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010468xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10469{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010470 int ret;
10471 xmlRelaxNGPtr schema;
10472 xmlRelaxNGGrammarPtr grammar;
10473 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010474 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010475
10476 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010477 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010478
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010479 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010480 schema = ctxt->schema;
10481 grammar = schema->topgrammar;
10482 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010483 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10484 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010485 }
10486 state = xmlRelaxNGNewValidState(ctxt, NULL);
10487 ctxt->state = state;
10488 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010489 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010490 state = ctxt->state;
10491 node = state->seq;
10492 node = xmlRelaxNGSkipIgnored(ctxt, node);
10493 if (node != NULL) {
10494 if (ret != -1) {
10495 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10496 ret = -1;
10497 }
10498 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010499 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010500 int i;
10501 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010502
Daniel Veillard4c004142003-10-07 11:33:24 +000010503 for (i = 0; i < ctxt->states->nbState; i++) {
10504 state = ctxt->states->tabState[i];
10505 node = state->seq;
10506 node = xmlRelaxNGSkipIgnored(ctxt, node);
10507 if (node == NULL)
10508 tmp = 0;
10509 xmlRelaxNGFreeValidState(ctxt, state);
10510 }
10511 if (tmp == -1) {
10512 if (ret != -1) {
10513 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10514 ret = -1;
10515 }
10516 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010517 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010518 if (ctxt->state != NULL) {
10519 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010520 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010521 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010522 if (ret != 0)
10523 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010524#ifdef DEBUG
10525 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010526 ctxt->error(ctxt->userData,
10527 "%d Extra error messages left on stack !\n",
10528 ctxt->errNr);
10529 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010530 }
10531#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010532#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010533 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010534 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010535
Daniel Veillard4c004142003-10-07 11:33:24 +000010536 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10537 vctxt.valid = 1;
10538 vctxt.error = ctxt->error;
10539 vctxt.warning = ctxt->warning;
10540 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010541
Daniel Veillard4c004142003-10-07 11:33:24 +000010542 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10543 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010544 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010545#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010546 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010547 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010548
Daniel Veillard4c004142003-10-07 11:33:24 +000010549 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010550}
10551
Daniel Veillardfd573f12003-03-16 17:52:32 +000010552/************************************************************************
10553 * *
10554 * Validation interfaces *
10555 * *
10556 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010557
Daniel Veillard6eadf632003-01-23 18:29:16 +000010558/**
10559 * xmlRelaxNGNewValidCtxt:
10560 * @schema: a precompiled XML RelaxNGs
10561 *
10562 * Create an XML RelaxNGs validation context based on the given schema
10563 *
10564 * Returns the validation context or NULL in case of error
10565 */
10566xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010567xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10568{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010569 xmlRelaxNGValidCtxtPtr ret;
10570
10571 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10572 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010573 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010574 return (NULL);
10575 }
10576 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10577 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010578 ret->error = xmlGenericError;
10579 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010580 ret->errNr = 0;
10581 ret->errMax = 0;
10582 ret->err = NULL;
10583 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010584 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010585 ret->states = NULL;
10586 ret->freeState = NULL;
10587 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010588 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010589 return (ret);
10590}
10591
10592/**
10593 * xmlRelaxNGFreeValidCtxt:
10594 * @ctxt: the schema validation context
10595 *
10596 * Free the resources associated to the schema validation context
10597 */
10598void
Daniel Veillard4c004142003-10-07 11:33:24 +000010599xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10600{
Daniel Veillard798024a2003-03-19 10:36:09 +000010601 int k;
10602
Daniel Veillard6eadf632003-01-23 18:29:16 +000010603 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010604 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010605 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010606 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010607 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010608 for (k = 0; k < ctxt->freeState->nbState; k++) {
10609 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10610 }
10611 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010612 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010613 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010614 for (k = 0; k < ctxt->freeStatesNr; k++) {
10615 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10616 }
10617 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010618 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010619 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010620 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010621 if (ctxt->elemTab != NULL) {
10622 xmlRegExecCtxtPtr exec;
10623
Daniel Veillard4c004142003-10-07 11:33:24 +000010624 exec = xmlRelaxNGElemPop(ctxt);
10625 while (exec != NULL) {
10626 xmlRegFreeExecCtxt(exec);
10627 exec = xmlRelaxNGElemPop(ctxt);
10628 }
10629 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010630 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010631 xmlFree(ctxt);
10632}
10633
10634/**
10635 * xmlRelaxNGSetValidErrors:
10636 * @ctxt: a Relax-NG validation context
10637 * @err: the error function
10638 * @warn: the warning function
10639 * @ctx: the functions context
10640 *
10641 * Set the error and warning callback informations
10642 */
10643void
10644xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010645 xmlRelaxNGValidityErrorFunc err,
10646 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10647{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010648 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010649 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010650 ctxt->error = err;
10651 ctxt->warning = warn;
10652 ctxt->userData = ctx;
10653}
10654
10655/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010656 * xmlRelaxNGGetValidErrors:
10657 * @ctxt: a Relax-NG validation context
10658 * @err: the error function result
10659 * @warn: the warning function result
10660 * @ctx: the functions context result
10661 *
10662 * Get the error and warning callback informations
10663 *
10664 * Returns -1 in case of error and 0 otherwise
10665 */
10666int
10667xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010668 xmlRelaxNGValidityErrorFunc * err,
10669 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10670{
Daniel Veillard409a8142003-07-18 15:16:57 +000010671 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010672 return (-1);
10673 if (err != NULL)
10674 *err = ctxt->error;
10675 if (warn != NULL)
10676 *warn = ctxt->warning;
10677 if (ctx != NULL)
10678 *ctx = ctxt->userData;
10679 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010680}
10681
10682/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010683 * xmlRelaxNGValidateDoc:
10684 * @ctxt: a Relax-NG validation context
10685 * @doc: a parsed document tree
10686 *
10687 * Validate a document tree in memory.
10688 *
10689 * Returns 0 if the document is valid, a positive error code
10690 * number otherwise and -1 in case of internal or API error.
10691 */
10692int
Daniel Veillard4c004142003-10-07 11:33:24 +000010693xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10694{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010695 int ret;
10696
10697 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010698 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010699
10700 ctxt->doc = doc;
10701
10702 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010703 /*
10704 * TODO: build error codes
10705 */
10706 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010707 return (1);
10708 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010709}
10710
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010711#define bottom_relaxng
10712#include "elfgcchack.h"
Daniel Veillard6eadf632003-01-23 18:29:16 +000010713#endif /* LIBXML_SCHEMAS_ENABLED */