blob: af4de868f36065d7ebb2fc129300462534dc7afe [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)) {
6132 if (flags & XML_RELAXNG_IN_LIST) {
6133 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6134 "Found forbidden pattern list//ref\n", NULL,
6135 NULL);
6136 }
6137 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6138 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6139 "Found forbidden pattern data/except//ref\n",
6140 NULL, NULL);
6141 }
6142 if (cur->depth > -4) {
6143 cur->depth = -4;
6144 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6145 flags, cur->type);
6146 cur->depth = ret - 15;
6147 } else if (cur->depth == -4) {
6148 ret = XML_RELAXNG_CONTENT_COMPLEX;
6149 } else {
6150 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6151 }
6152 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6153 /*
6154 * The 7.3 Attribute derivation rule for groups is plugged there
6155 */
6156 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6157 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6158 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6159 "Found forbidden pattern data/except//element(ref)\n",
6160 NULL, NULL);
6161 }
6162 if (flags & XML_RELAXNG_IN_LIST) {
6163 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6164 "Found forbidden pattern list//element(ref)\n",
6165 NULL, NULL);
6166 }
6167 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6168 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6169 "Found forbidden pattern attribute//element(ref)\n",
6170 NULL, NULL);
6171 }
6172 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6173 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6174 "Found forbidden pattern attribute//element(ref)\n",
6175 NULL, NULL);
6176 }
6177 /*
6178 * reset since in the simple form elements are only child
6179 * of grammar/define
6180 */
6181 nflags = 0;
6182 ret =
6183 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6184 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6185 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6186 "Element %s attributes have a content type error\n",
6187 cur->name, NULL);
6188 }
6189 ret =
6190 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6191 cur->type);
6192 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6193 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6194 "Element %s has a content type error\n",
6195 cur->name, NULL);
6196 } else {
6197 ret = XML_RELAXNG_CONTENT_COMPLEX;
6198 }
6199 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6200 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6201 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6202 "Found forbidden pattern attribute//attribute\n",
6203 NULL, NULL);
6204 }
6205 if (flags & XML_RELAXNG_IN_LIST) {
6206 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6207 "Found forbidden pattern list//attribute\n",
6208 NULL, NULL);
6209 }
6210 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6211 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6212 "Found forbidden pattern oneOrMore//group//attribute\n",
6213 NULL, NULL);
6214 }
6215 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6216 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6217 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6218 NULL, NULL);
6219 }
6220 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6221 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6222 "Found forbidden pattern data/except//attribute\n",
6223 NULL, NULL);
6224 }
6225 if (flags & XML_RELAXNG_IN_START) {
6226 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6227 "Found forbidden pattern start//attribute\n",
6228 NULL, NULL);
6229 }
6230 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6231 && (cur->name == NULL)) {
6232 if (cur->ns == NULL) {
6233 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6234 "Found anyName attribute without oneOrMore ancestor\n",
6235 NULL, NULL);
6236 } else {
6237 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6238 "Found nsName attribute without oneOrMore ancestor\n",
6239 NULL, NULL);
6240 }
6241 }
6242 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6243 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6244 ret = XML_RELAXNG_CONTENT_EMPTY;
6245 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6246 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6247 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6248 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6249 "Found forbidden pattern data/except//oneOrMore\n",
6250 NULL, NULL);
6251 }
6252 if (flags & XML_RELAXNG_IN_START) {
6253 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6254 "Found forbidden pattern start//oneOrMore\n",
6255 NULL, NULL);
6256 }
6257 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6258 ret =
6259 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6260 cur->type);
6261 ret = xmlRelaxNGGroupContentType(ret, ret);
6262 } else if (cur->type == XML_RELAXNG_LIST) {
6263 if (flags & XML_RELAXNG_IN_LIST) {
6264 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6265 "Found forbidden pattern list//list\n", NULL,
6266 NULL);
6267 }
6268 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6269 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6270 "Found forbidden pattern data/except//list\n",
6271 NULL, NULL);
6272 }
6273 if (flags & XML_RELAXNG_IN_START) {
6274 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6275 "Found forbidden pattern start//list\n", NULL,
6276 NULL);
6277 }
6278 nflags = flags | XML_RELAXNG_IN_LIST;
6279 ret =
6280 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6281 cur->type);
6282 } else if (cur->type == XML_RELAXNG_GROUP) {
6283 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6284 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6285 "Found forbidden pattern data/except//group\n",
6286 NULL, NULL);
6287 }
6288 if (flags & XML_RELAXNG_IN_START) {
6289 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6290 "Found forbidden pattern start//group\n", NULL,
6291 NULL);
6292 }
6293 if (flags & XML_RELAXNG_IN_ONEORMORE)
6294 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6295 else
6296 nflags = flags;
6297 ret =
6298 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6299 cur->type);
6300 /*
6301 * The 7.3 Attribute derivation rule for groups is plugged there
6302 */
6303 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6304 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6305 if (flags & XML_RELAXNG_IN_LIST) {
6306 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6307 "Found forbidden pattern list//interleave\n",
6308 NULL, NULL);
6309 }
6310 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6311 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6312 "Found forbidden pattern data/except//interleave\n",
6313 NULL, NULL);
6314 }
6315 if (flags & XML_RELAXNG_IN_START) {
6316 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6317 "Found forbidden pattern start//interleave\n",
6318 NULL, NULL);
6319 }
6320 if (flags & XML_RELAXNG_IN_ONEORMORE)
6321 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6322 else
6323 nflags = flags;
6324 ret =
6325 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6326 cur->type);
6327 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6328 if ((cur->parent != NULL) &&
6329 (cur->parent->type == XML_RELAXNG_DATATYPE))
6330 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6331 else
6332 nflags = flags;
6333 ret =
6334 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6335 cur->type);
6336 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6337 if (flags & XML_RELAXNG_IN_START) {
6338 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6339 "Found forbidden pattern start//data\n", NULL,
6340 NULL);
6341 }
6342 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6343 ret = XML_RELAXNG_CONTENT_SIMPLE;
6344 } else if (cur->type == XML_RELAXNG_VALUE) {
6345 if (flags & XML_RELAXNG_IN_START) {
6346 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6347 "Found forbidden pattern start//value\n", NULL,
6348 NULL);
6349 }
6350 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6351 ret = XML_RELAXNG_CONTENT_SIMPLE;
6352 } else if (cur->type == XML_RELAXNG_TEXT) {
6353 if (flags & XML_RELAXNG_IN_LIST) {
6354 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6355 "Found forbidden pattern list//text\n", NULL,
6356 NULL);
6357 }
6358 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6359 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6360 "Found forbidden pattern data/except//text\n",
6361 NULL, NULL);
6362 }
6363 if (flags & XML_RELAXNG_IN_START) {
6364 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6365 "Found forbidden pattern start//text\n", NULL,
6366 NULL);
6367 }
6368 ret = XML_RELAXNG_CONTENT_COMPLEX;
6369 } else if (cur->type == XML_RELAXNG_EMPTY) {
6370 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6371 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6372 "Found forbidden pattern data/except//empty\n",
6373 NULL, NULL);
6374 }
6375 if (flags & XML_RELAXNG_IN_START) {
6376 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6377 "Found forbidden pattern start//empty\n", NULL,
6378 NULL);
6379 }
6380 ret = XML_RELAXNG_CONTENT_EMPTY;
6381 } else if (cur->type == XML_RELAXNG_CHOICE) {
6382 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6383 ret =
6384 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6385 } else {
6386 ret =
6387 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6388 }
6389 cur = cur->next;
6390 if (ptype == XML_RELAXNG_GROUP) {
6391 val = xmlRelaxNGGroupContentType(val, ret);
6392 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6393 tmp = xmlRelaxNGGroupContentType(val, ret);
6394 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6395 tmp = xmlRelaxNGMaxContentType(val, ret);
6396 } else if (ptype == XML_RELAXNG_CHOICE) {
6397 val = xmlRelaxNGMaxContentType(val, ret);
6398 } else if (ptype == XML_RELAXNG_LIST) {
6399 val = XML_RELAXNG_CONTENT_SIMPLE;
6400 } else if (ptype == XML_RELAXNG_EXCEPT) {
6401 if (ret == XML_RELAXNG_CONTENT_ERROR)
6402 val = XML_RELAXNG_CONTENT_ERROR;
6403 else
6404 val = XML_RELAXNG_CONTENT_SIMPLE;
6405 } else {
6406 val = xmlRelaxNGGroupContentType(val, ret);
6407 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006408
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006409 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006410 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006411}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006412
6413/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006414 * xmlRelaxNGParseGrammar:
6415 * @ctxt: a Relax-NG parser context
6416 * @nodes: grammar children nodes
6417 *
6418 * parse a Relax-NG <grammar> node
6419 *
6420 * Returns the internal xmlRelaxNGGrammarPtr built or
6421 * NULL in case of error
6422 */
6423static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006424xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6425{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006426 xmlRelaxNGGrammarPtr ret, tmp, old;
6427
Daniel Veillardc482e262003-02-26 14:48:48 +00006428#ifdef DEBUG_GRAMMAR
6429 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6430#endif
6431
Daniel Veillard6eadf632003-01-23 18:29:16 +00006432 ret = xmlRelaxNGNewGrammar(ctxt);
6433 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006434 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006435
6436 /*
6437 * Link the new grammar in the tree
6438 */
6439 ret->parent = ctxt->grammar;
6440 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006441 tmp = ctxt->grammar->children;
6442 if (tmp == NULL) {
6443 ctxt->grammar->children = ret;
6444 } else {
6445 while (tmp->next != NULL)
6446 tmp = tmp->next;
6447 tmp->next = ret;
6448 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006449 }
6450
6451 old = ctxt->grammar;
6452 ctxt->grammar = ret;
6453 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6454 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006455 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006456 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6457 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006458 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006459 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6460 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006461 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006462
6463 /*
6464 * Apply 4.17 mergingd rules to defines and starts
6465 */
6466 xmlRelaxNGCombineStart(ctxt, ret);
6467 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006468 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6469 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006470 }
6471
6472 /*
6473 * link together defines and refs in this grammar
6474 */
6475 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006476 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6477 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006478 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006479
Daniel Veillard6eadf632003-01-23 18:29:16 +00006480 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006481 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006482}
6483
6484/**
6485 * xmlRelaxNGParseDocument:
6486 * @ctxt: a Relax-NG parser context
6487 * @node: the root node of the RelaxNG schema
6488 *
6489 * parse a Relax-NG definition resource and build an internal
6490 * xmlRelaxNG struture which can be used to validate instances.
6491 *
6492 * Returns the internal XML RelaxNG structure built or
6493 * NULL in case of error
6494 */
6495static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006496xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6497{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006498 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006499 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006500 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006501
6502 if ((ctxt == NULL) || (node == NULL))
6503 return (NULL);
6504
6505 schema = xmlRelaxNGNewRelaxNG(ctxt);
6506 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006507 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006508
Daniel Veillard276be4a2003-01-24 01:03:34 +00006509 olddefine = ctxt->define;
6510 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006511 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006512 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006513 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006514 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006515
Daniel Veillard4c004142003-10-07 11:33:24 +00006516 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6517 if (schema->topgrammar == NULL) {
6518 return (schema);
6519 }
6520 /*
6521 * Link the new grammar in the tree
6522 */
6523 ret->parent = ctxt->grammar;
6524 if (ctxt->grammar != NULL) {
6525 tmp = ctxt->grammar->children;
6526 if (tmp == NULL) {
6527 ctxt->grammar->children = ret;
6528 } else {
6529 while (tmp->next != NULL)
6530 tmp = tmp->next;
6531 tmp->next = ret;
6532 }
6533 }
6534 old = ctxt->grammar;
6535 ctxt->grammar = ret;
6536 xmlRelaxNGParseStart(ctxt, node);
6537 if (old != NULL)
6538 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006539 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006540 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006541 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006542 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6543 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6544 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6545 while ((schema->topgrammar->start != NULL) &&
6546 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6547 (schema->topgrammar->start->next != NULL))
6548 schema->topgrammar->start =
6549 schema->topgrammar->start->content;
6550 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6551 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6552 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006553 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006554#ifdef DEBUG
6555 if (schema == NULL)
6556 xmlGenericError(xmlGenericErrorContext,
6557 "xmlRelaxNGParseDocument() failed\n");
6558#endif
6559
6560 return (schema);
6561}
6562
6563/************************************************************************
6564 * *
6565 * Reading RelaxNGs *
6566 * *
6567 ************************************************************************/
6568
6569/**
6570 * xmlRelaxNGNewParserCtxt:
6571 * @URL: the location of the schema
6572 *
6573 * Create an XML RelaxNGs parse context for that file/resource expected
6574 * to contain an XML RelaxNGs file.
6575 *
6576 * Returns the parser context or NULL in case of error
6577 */
6578xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006579xmlRelaxNGNewParserCtxt(const char *URL)
6580{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006581 xmlRelaxNGParserCtxtPtr ret;
6582
6583 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006584 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006585
Daniel Veillard4c004142003-10-07 11:33:24 +00006586 ret =
6587 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006588 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006589 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006590 return (NULL);
6591 }
6592 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006593 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006594 ret->error = xmlGenericError;
6595 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006596 return (ret);
6597}
6598
6599/**
6600 * xmlRelaxNGNewMemParserCtxt:
6601 * @buffer: a pointer to a char array containing the schemas
6602 * @size: the size of the array
6603 *
6604 * Create an XML RelaxNGs parse context for that memory buffer expected
6605 * to contain an XML RelaxNGs file.
6606 *
6607 * Returns the parser context or NULL in case of error
6608 */
6609xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006610xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6611{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006612 xmlRelaxNGParserCtxtPtr ret;
6613
6614 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006615 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006616
Daniel Veillard4c004142003-10-07 11:33:24 +00006617 ret =
6618 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006619 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006620 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006621 return (NULL);
6622 }
6623 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6624 ret->buffer = buffer;
6625 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006626 ret->error = xmlGenericError;
6627 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006628 return (ret);
6629}
6630
6631/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006632 * xmlRelaxNGNewDocParserCtxt:
6633 * @doc: a preparsed document tree
6634 *
6635 * Create an XML RelaxNGs parser context for that document.
6636 * Note: since the process of compiling a RelaxNG schemas modifies the
6637 * document, the @doc parameter is duplicated internally.
6638 *
6639 * Returns the parser context or NULL in case of error
6640 */
6641xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006642xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6643{
Daniel Veillard33300b42003-04-17 09:09:19 +00006644 xmlRelaxNGParserCtxtPtr ret;
6645 xmlDocPtr copy;
6646
6647 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006648 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006649 copy = xmlCopyDoc(doc, 1);
6650 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006651 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006652
Daniel Veillard4c004142003-10-07 11:33:24 +00006653 ret =
6654 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006655 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006656 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006657 return (NULL);
6658 }
6659 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6660 ret->document = copy;
Daniel Veillard42595322004-11-08 10:52:06 +00006661 ret->freedoc = 1;
Daniel Veillard33300b42003-04-17 09:09:19 +00006662 ret->userData = xmlGenericErrorContext;
6663 return (ret);
6664}
6665
6666/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006667 * xmlRelaxNGFreeParserCtxt:
6668 * @ctxt: the schema parser context
6669 *
6670 * Free the resources associated to the schema parser context
6671 */
6672void
Daniel Veillard4c004142003-10-07 11:33:24 +00006673xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6674{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006675 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006676 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006677 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006678 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006679 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006680 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006681 if (ctxt->interleaves != NULL)
6682 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006683 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006684 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006685 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006686 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006687 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006688 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006689 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006690 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006691 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006692 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006693
Daniel Veillard4c004142003-10-07 11:33:24 +00006694 for (i = 0; i < ctxt->defNr; i++)
6695 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6696 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006697 }
Daniel Veillard42595322004-11-08 10:52:06 +00006698 if ((ctxt->document != NULL) && (ctxt->freedoc))
6699 xmlFreeDoc(ctxt->document);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006700 xmlFree(ctxt);
6701}
6702
Daniel Veillard6eadf632003-01-23 18:29:16 +00006703/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006704 * xmlRelaxNGNormExtSpace:
6705 * @value: a value
6706 *
6707 * Removes the leading and ending spaces of the value
6708 * The string is modified "in situ"
6709 */
6710static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006711xmlRelaxNGNormExtSpace(xmlChar * value)
6712{
Daniel Veillardd2298792003-02-14 16:54:11 +00006713 xmlChar *start = value;
6714 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006715
Daniel Veillard4c004142003-10-07 11:33:24 +00006716 if (value == NULL)
6717 return;
6718
William M. Brack76e95df2003-10-18 16:20:14 +00006719 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006720 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006721 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006722 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006723 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006724 cur++;
6725 if (*cur == 0)
6726 return;
6727 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006728 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006729 cur++;
6730 if (*cur == 0) {
6731 *start = 0;
6732 return;
6733 }
6734 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006735 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006736 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006737 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006738 *start++ = *cur++;
6739 if (*cur == 0) {
6740 *start = 0;
6741 return;
6742 }
6743 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006744 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006745 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006746 if (*cur == 0) {
6747 *start = 0;
6748 return;
6749 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006750 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006751 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006752 }
6753}
6754
6755/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006756 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006757 * @ctxt: a Relax-NG parser context
6758 * @node: a Relax-NG node
6759 *
6760 * Check all the attributes on the given node
6761 */
6762static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006763xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6764{
Daniel Veillardd2298792003-02-14 16:54:11 +00006765 xmlAttrPtr cur, next;
6766
6767 cur = node->properties;
6768 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006769 next = cur->next;
6770 if ((cur->ns == NULL) ||
6771 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6772 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6773 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6774 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6775 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6776 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6777 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6778 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6779 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6780 "Attribute %s is not allowed on %s\n",
6781 cur->name, node->name);
6782 }
6783 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6784 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6785 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
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 "href")) {
6791 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6792 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
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 "combine")) {
6798 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6799 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
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 "datatypeLibrary")) {
6805 xmlChar *val;
6806 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006807
Daniel Veillard4c004142003-10-07 11:33:24 +00006808 val = xmlNodeListGetString(node->doc, cur->children, 1);
6809 if (val != NULL) {
6810 if (val[0] != 0) {
6811 uri = xmlParseURI((const char *) val);
6812 if (uri == NULL) {
6813 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6814 "Attribute %s contains invalid URI %s\n",
6815 cur->name, val);
6816 } else {
6817 if (uri->scheme == NULL) {
6818 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6819 "Attribute %s URI %s is not absolute\n",
6820 cur->name, val);
6821 }
6822 if (uri->fragment != NULL) {
6823 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6824 "Attribute %s URI %s has a fragment ID\n",
6825 cur->name, val);
6826 }
6827 xmlFreeURI(uri);
6828 }
6829 }
6830 xmlFree(val);
6831 }
6832 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6833 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6834 "Unknown attribute %s on %s\n", cur->name,
6835 node->name);
6836 }
6837 }
6838 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006839 }
6840}
6841
6842/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006843 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006844 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006845 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006846 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006847 * Cleanup the subtree from unwanted nodes for parsing, resolve
6848 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006849 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006850static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006851xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6852{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006853 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006854
Daniel Veillard6eadf632003-01-23 18:29:16 +00006855 delete = NULL;
6856 cur = root;
6857 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006858 if (delete != NULL) {
6859 xmlUnlinkNode(delete);
6860 xmlFreeNode(delete);
6861 delete = NULL;
6862 }
6863 if (cur->type == XML_ELEMENT_NODE) {
6864 /*
6865 * Simplification 4.1. Annotations
6866 */
6867 if ((cur->ns == NULL) ||
6868 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6869 if ((cur->parent != NULL) &&
6870 (cur->parent->type == XML_ELEMENT_NODE) &&
6871 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6872 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6873 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6874 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6875 "element %s doesn't allow foreign elements\n",
6876 cur->parent->name, NULL);
6877 }
6878 delete = cur;
6879 goto skip_children;
6880 } else {
6881 xmlRelaxNGCleanupAttributes(ctxt, cur);
6882 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6883 xmlChar *href, *ns, *base, *URL;
6884 xmlRelaxNGDocumentPtr docu;
6885 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006886 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006887
Daniel Veillard4c004142003-10-07 11:33:24 +00006888 ns = xmlGetProp(cur, BAD_CAST "ns");
6889 if (ns == NULL) {
6890 tmp = cur->parent;
6891 while ((tmp != NULL) &&
6892 (tmp->type == XML_ELEMENT_NODE)) {
6893 ns = xmlGetProp(tmp, BAD_CAST "ns");
6894 if (ns != NULL)
6895 break;
6896 tmp = tmp->parent;
6897 }
6898 }
6899 href = xmlGetProp(cur, BAD_CAST "href");
6900 if (href == NULL) {
6901 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6902 "xmlRelaxNGParse: externalRef has no href attribute\n",
6903 NULL, NULL);
6904 delete = cur;
6905 goto skip_children;
6906 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006907 uri = xmlParseURI((const char *) href);
6908 if (uri == NULL) {
6909 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6910 "Incorrect URI for externalRef %s\n",
6911 href, NULL);
6912 if (href != NULL)
6913 xmlFree(href);
6914 delete = cur;
6915 goto skip_children;
6916 }
6917 if (uri->fragment != NULL) {
6918 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6919 "Fragment forbidden in URI for externalRef %s\n",
6920 href, NULL);
6921 xmlFreeURI(uri);
6922 if (href != NULL)
6923 xmlFree(href);
6924 delete = cur;
6925 goto skip_children;
6926 }
6927 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006928 base = xmlNodeGetBase(cur->doc, cur);
6929 URL = xmlBuildURI(href, base);
6930 if (URL == NULL) {
6931 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6932 "Failed to compute URL for externalRef %s\n",
6933 href, NULL);
6934 if (href != NULL)
6935 xmlFree(href);
6936 if (base != NULL)
6937 xmlFree(base);
6938 delete = cur;
6939 goto skip_children;
6940 }
6941 if (href != NULL)
6942 xmlFree(href);
6943 if (base != NULL)
6944 xmlFree(base);
6945 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6946 if (docu == NULL) {
6947 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6948 "Failed to load externalRef %s\n", URL,
6949 NULL);
6950 xmlFree(URL);
6951 delete = cur;
6952 goto skip_children;
6953 }
6954 if (ns != NULL)
6955 xmlFree(ns);
6956 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006957 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006958 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6959 xmlChar *href, *ns, *base, *URL;
6960 xmlRelaxNGIncludePtr incl;
6961 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006962
Daniel Veillard4c004142003-10-07 11:33:24 +00006963 href = xmlGetProp(cur, BAD_CAST "href");
6964 if (href == NULL) {
6965 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6966 "xmlRelaxNGParse: include has no href attribute\n",
6967 NULL, NULL);
6968 delete = cur;
6969 goto skip_children;
6970 }
6971 base = xmlNodeGetBase(cur->doc, cur);
6972 URL = xmlBuildURI(href, base);
6973 if (URL == NULL) {
6974 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6975 "Failed to compute URL for include %s\n",
6976 href, NULL);
6977 if (href != NULL)
6978 xmlFree(href);
6979 if (base != NULL)
6980 xmlFree(base);
6981 delete = cur;
6982 goto skip_children;
6983 }
6984 if (href != NULL)
6985 xmlFree(href);
6986 if (base != NULL)
6987 xmlFree(base);
6988 ns = xmlGetProp(cur, BAD_CAST "ns");
6989 if (ns == NULL) {
6990 tmp = cur->parent;
6991 while ((tmp != NULL) &&
6992 (tmp->type == XML_ELEMENT_NODE)) {
6993 ns = xmlGetProp(tmp, BAD_CAST "ns");
6994 if (ns != NULL)
6995 break;
6996 tmp = tmp->parent;
6997 }
6998 }
6999 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7000 if (ns != NULL)
7001 xmlFree(ns);
7002 if (incl == NULL) {
7003 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7004 "Failed to load include %s\n", URL,
7005 NULL);
7006 xmlFree(URL);
7007 delete = cur;
7008 goto skip_children;
7009 }
7010 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007011 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007012 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7013 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7014 {
7015 xmlChar *name, *ns;
7016 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007017
Daniel Veillard4c004142003-10-07 11:33:24 +00007018 /*
7019 * Simplification 4.8. name attribute of element
7020 * and attribute elements
7021 */
7022 name = xmlGetProp(cur, BAD_CAST "name");
7023 if (name != NULL) {
7024 if (cur->children == NULL) {
7025 text =
7026 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7027 name);
7028 } else {
7029 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007030
Daniel Veillard03a53c32004-10-26 16:06:51 +00007031 node = xmlNewDocNode(cur->doc, cur->ns,
7032 BAD_CAST "name", NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00007033 if (node != NULL) {
7034 xmlAddPrevSibling(cur->children, node);
7035 text = xmlNewText(name);
7036 xmlAddChild(node, text);
7037 text = node;
7038 }
7039 }
7040 if (text == NULL) {
7041 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7042 "Failed to create a name %s element\n",
7043 name, NULL);
7044 }
7045 xmlUnsetProp(cur, BAD_CAST "name");
7046 xmlFree(name);
7047 ns = xmlGetProp(cur, BAD_CAST "ns");
7048 if (ns != NULL) {
7049 if (text != NULL) {
7050 xmlSetProp(text, BAD_CAST "ns", ns);
7051 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7052 }
7053 xmlFree(ns);
7054 } else if (xmlStrEqual(cur->name,
7055 BAD_CAST "attribute")) {
7056 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7057 }
7058 }
7059 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7060 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7061 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7062 /*
7063 * Simplification 4.8. name attribute of element
7064 * and attribute elements
7065 */
7066 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7067 xmlNodePtr node;
7068 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007069
Daniel Veillard4c004142003-10-07 11:33:24 +00007070 node = cur->parent;
7071 while ((node != NULL) &&
7072 (node->type == XML_ELEMENT_NODE)) {
7073 ns = xmlGetProp(node, BAD_CAST "ns");
7074 if (ns != NULL) {
7075 break;
7076 }
7077 node = node->parent;
7078 }
7079 if (ns == NULL) {
7080 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7081 } else {
7082 xmlSetProp(cur, BAD_CAST "ns", ns);
7083 xmlFree(ns);
7084 }
7085 }
7086 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7087 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007088
Daniel Veillard4c004142003-10-07 11:33:24 +00007089 /*
7090 * Simplification: 4.10. QNames
7091 */
7092 name = xmlNodeGetContent(cur);
7093 if (name != NULL) {
7094 local = xmlSplitQName2(name, &prefix);
7095 if (local != NULL) {
7096 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007097
Daniel Veillard4c004142003-10-07 11:33:24 +00007098 ns = xmlSearchNs(cur->doc, cur, prefix);
7099 if (ns == NULL) {
7100 xmlRngPErr(ctxt, cur,
7101 XML_RNGP_PREFIX_UNDEFINED,
7102 "xmlRelaxNGParse: no namespace for prefix %s\n",
7103 prefix, NULL);
7104 } else {
7105 xmlSetProp(cur, BAD_CAST "ns",
7106 ns->href);
7107 xmlNodeSetContent(cur, local);
7108 }
7109 xmlFree(local);
7110 xmlFree(prefix);
7111 }
7112 xmlFree(name);
7113 }
7114 }
7115 /*
7116 * 4.16
7117 */
7118 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7119 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7120 xmlRngPErr(ctxt, cur,
7121 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7122 "Found nsName/except//nsName forbidden construct\n",
7123 NULL, NULL);
7124 }
7125 }
7126 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7127 (cur != root)) {
7128 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007129
Daniel Veillard4c004142003-10-07 11:33:24 +00007130 /*
7131 * 4.16
7132 */
7133 if ((cur->parent != NULL) &&
7134 (xmlStrEqual
7135 (cur->parent->name, BAD_CAST "anyName"))) {
7136 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7137 xmlRelaxNGCleanupTree(ctxt, cur);
7138 ctxt->flags = oldflags;
7139 goto skip_children;
7140 } else if ((cur->parent != NULL) &&
7141 (xmlStrEqual
7142 (cur->parent->name, BAD_CAST "nsName"))) {
7143 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7144 xmlRelaxNGCleanupTree(ctxt, cur);
7145 ctxt->flags = oldflags;
7146 goto skip_children;
7147 }
7148 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7149 /*
7150 * 4.16
7151 */
7152 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7153 xmlRngPErr(ctxt, cur,
7154 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7155 "Found anyName/except//anyName forbidden construct\n",
7156 NULL, NULL);
7157 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7158 xmlRngPErr(ctxt, cur,
7159 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7160 "Found nsName/except//anyName forbidden construct\n",
7161 NULL, NULL);
7162 }
7163 }
7164 /*
7165 * Thisd is not an else since "include" is transformed
7166 * into a div
7167 */
7168 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7169 xmlChar *ns;
7170 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007171
Daniel Veillard4c004142003-10-07 11:33:24 +00007172 /*
7173 * implements rule 4.11
7174 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007175
Daniel Veillard4c004142003-10-07 11:33:24 +00007176 ns = xmlGetProp(cur, BAD_CAST "ns");
7177
7178 child = cur->children;
7179 ins = cur;
7180 while (child != NULL) {
7181 if (ns != NULL) {
7182 if (!xmlHasProp(child, BAD_CAST "ns")) {
7183 xmlSetProp(child, BAD_CAST "ns", ns);
7184 }
7185 }
7186 tmp = child->next;
7187 xmlUnlinkNode(child);
7188 ins = xmlAddNextSibling(ins, child);
7189 child = tmp;
7190 }
7191 if (ns != NULL)
7192 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007193 /*
7194 * Since we are about to delete cur, if it's nsDef is non-NULL we
7195 * need to preserve it (it contains the ns definitions for the
7196 * children we just moved). We'll just stick it on to the end
7197 * of cur->parent's list, since it's never going to be re-serialized
7198 * (bug 143738).
7199 */
7200 if (cur->nsDef != NULL) {
7201 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7202 while (parDef->next != NULL)
7203 parDef = parDef->next;
7204 parDef->next = cur->nsDef;
7205 cur->nsDef = NULL;
7206 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007207 delete = cur;
7208 goto skip_children;
7209 }
7210 }
7211 }
7212 /*
7213 * Simplification 4.2 whitespaces
7214 */
7215 else if ((cur->type == XML_TEXT_NODE) ||
7216 (cur->type == XML_CDATA_SECTION_NODE)) {
7217 if (IS_BLANK_NODE(cur)) {
7218 if (cur->parent->type == XML_ELEMENT_NODE) {
7219 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7220 &&
7221 (!xmlStrEqual
7222 (cur->parent->name, BAD_CAST "param")))
7223 delete = cur;
7224 } else {
7225 delete = cur;
7226 goto skip_children;
7227 }
7228 }
7229 } else {
7230 delete = cur;
7231 goto skip_children;
7232 }
7233
7234 /*
7235 * Skip to next node
7236 */
7237 if (cur->children != NULL) {
7238 if ((cur->children->type != XML_ENTITY_DECL) &&
7239 (cur->children->type != XML_ENTITY_REF_NODE) &&
7240 (cur->children->type != XML_ENTITY_NODE)) {
7241 cur = cur->children;
7242 continue;
7243 }
7244 }
7245 skip_children:
7246 if (cur->next != NULL) {
7247 cur = cur->next;
7248 continue;
7249 }
7250
7251 do {
7252 cur = cur->parent;
7253 if (cur == NULL)
7254 break;
7255 if (cur == root) {
7256 cur = NULL;
7257 break;
7258 }
7259 if (cur->next != NULL) {
7260 cur = cur->next;
7261 break;
7262 }
7263 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007264 }
7265 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007266 xmlUnlinkNode(delete);
7267 xmlFreeNode(delete);
7268 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007269 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007270}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007271
Daniel Veillardc5312d72003-02-21 17:14:10 +00007272/**
7273 * xmlRelaxNGCleanupDoc:
7274 * @ctxt: a Relax-NG parser context
7275 * @doc: an xmldocPtr document pointer
7276 *
7277 * Cleanup the document from unwanted nodes for parsing, resolve
7278 * Include and externalRef lookups.
7279 *
7280 * Returns the cleaned up document or NULL in case of error
7281 */
7282static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007283xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7284{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007285 xmlNodePtr root;
7286
7287 /*
7288 * Extract the root
7289 */
7290 root = xmlDocGetRootElement(doc);
7291 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007292 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7293 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007294 return (NULL);
7295 }
7296 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007297 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007298}
7299
7300/**
7301 * xmlRelaxNGParse:
7302 * @ctxt: a Relax-NG parser context
7303 *
7304 * parse a schema definition resource and build an internal
7305 * XML Shema struture which can be used to validate instances.
7306 * *WARNING* this interface is highly subject to change
7307 *
7308 * Returns the internal XML RelaxNG structure built from the resource or
7309 * NULL in case of error
7310 */
7311xmlRelaxNGPtr
7312xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7313{
7314 xmlRelaxNGPtr ret = NULL;
7315 xmlDocPtr doc;
7316 xmlNodePtr root;
7317
7318 xmlRelaxNGInitTypes();
7319
7320 if (ctxt == NULL)
7321 return (NULL);
7322
7323 /*
7324 * First step is to parse the input document into an DOM/Infoset
7325 */
7326 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007327 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007328 if (doc == NULL) {
7329 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7330 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7331 NULL);
7332 return (NULL);
7333 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007334 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007335 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007336 if (doc == NULL) {
7337 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7338 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7339 NULL);
7340 return (NULL);
7341 }
7342 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7343 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007344 } else if (ctxt->document != NULL) {
7345 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007346 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007347 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7348 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7349 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007350 }
7351 ctxt->document = doc;
7352
7353 /*
7354 * Some preprocessing of the document content
7355 */
7356 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7357 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007358 xmlFreeDoc(ctxt->document);
7359 ctxt->document = NULL;
7360 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007361 }
7362
Daniel Veillard6eadf632003-01-23 18:29:16 +00007363 /*
7364 * Then do the parsing for good
7365 */
7366 root = xmlDocGetRootElement(doc);
7367 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007368 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7369 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7370 ctxt->URL, NULL);
7371 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007372 return (NULL);
7373 }
7374 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007375 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007376 xmlFreeDoc(doc);
7377 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007378 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007379
7380 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007381 * Check the ref/defines links
7382 */
7383 /*
7384 * try to preprocess interleaves
7385 */
7386 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007387 xmlHashScan(ctxt->interleaves,
7388 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007389 }
7390
7391 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007392 * if there was a parsing error return NULL
7393 */
7394 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007395 xmlRelaxNGFree(ret);
7396 ctxt->document = NULL;
7397 xmlFreeDoc(doc);
7398 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007399 }
7400
7401 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007402 * try to compile (parts of) the schemas
7403 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007404 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7405 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007406 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007407
Daniel Veillard4c004142003-10-07 11:33:24 +00007408 def = xmlRelaxNGNewDefine(ctxt, NULL);
7409 if (def != NULL) {
7410 def->type = XML_RELAXNG_START;
7411 def->content = ret->topgrammar->start;
7412 ret->topgrammar->start = def;
7413 }
7414 }
7415 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007416 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007417
7418 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007419 * Transfer the pointer for cleanup at the schema level.
7420 */
7421 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007422 ctxt->document = NULL;
7423 ret->documents = ctxt->documents;
7424 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007425
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007426 ret->includes = ctxt->includes;
7427 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007428 ret->defNr = ctxt->defNr;
7429 ret->defTab = ctxt->defTab;
7430 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007431 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007432 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007433
7434 return (ret);
7435}
Daniel Veillard4c004142003-10-07 11:33:24 +00007436
Daniel Veillard6eadf632003-01-23 18:29:16 +00007437/**
7438 * xmlRelaxNGSetParserErrors:
7439 * @ctxt: a Relax-NG validation context
7440 * @err: the error callback
7441 * @warn: the warning callback
7442 * @ctx: contextual data for the callbacks
7443 *
7444 * Set the callback functions used to handle errors for a validation context
7445 */
7446void
7447xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007448 xmlRelaxNGValidityErrorFunc err,
7449 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7450{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007451 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007452 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007453 ctxt->error = err;
7454 ctxt->warning = warn;
7455 ctxt->userData = ctx;
7456}
Daniel Veillard409a8142003-07-18 15:16:57 +00007457
7458/**
7459 * xmlRelaxNGGetParserErrors:
7460 * @ctxt: a Relax-NG validation context
7461 * @err: the error callback result
7462 * @warn: the warning callback result
7463 * @ctx: contextual data for the callbacks result
7464 *
7465 * Get the callback information used to handle errors for a validation context
7466 *
7467 * Returns -1 in case of failure, 0 otherwise.
7468 */
7469int
7470xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007471 xmlRelaxNGValidityErrorFunc * err,
7472 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7473{
Daniel Veillard409a8142003-07-18 15:16:57 +00007474 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007475 return (-1);
7476 if (err != NULL)
7477 *err = ctxt->error;
7478 if (warn != NULL)
7479 *warn = ctxt->warning;
7480 if (ctx != NULL)
7481 *ctx = ctxt->userData;
7482 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007483}
7484
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007485#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007486
Daniel Veillard6eadf632003-01-23 18:29:16 +00007487/************************************************************************
7488 * *
7489 * Dump back a compiled form *
7490 * *
7491 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007492static void xmlRelaxNGDumpDefine(FILE * output,
7493 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007494
7495/**
7496 * xmlRelaxNGDumpDefines:
7497 * @output: the file output
7498 * @defines: a list of define structures
7499 *
7500 * Dump a RelaxNG structure back
7501 */
7502static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007503xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7504{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007505 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007506 xmlRelaxNGDumpDefine(output, defines);
7507 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007508 }
7509}
7510
7511/**
7512 * xmlRelaxNGDumpDefine:
7513 * @output: the file output
7514 * @define: a define structure
7515 *
7516 * Dump a RelaxNG structure back
7517 */
7518static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007519xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7520{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007521 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007522 return;
7523 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007524 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007525 fprintf(output, "<empty/>\n");
7526 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007527 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007528 fprintf(output, "<notAllowed/>\n");
7529 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007530 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007531 fprintf(output, "<text/>\n");
7532 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007533 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007534 fprintf(output, "<element>\n");
7535 if (define->name != NULL) {
7536 fprintf(output, "<name");
7537 if (define->ns != NULL)
7538 fprintf(output, " ns=\"%s\"", define->ns);
7539 fprintf(output, ">%s</name>\n", define->name);
7540 }
7541 xmlRelaxNGDumpDefines(output, define->attrs);
7542 xmlRelaxNGDumpDefines(output, define->content);
7543 fprintf(output, "</element>\n");
7544 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007545 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007546 fprintf(output, "<list>\n");
7547 xmlRelaxNGDumpDefines(output, define->content);
7548 fprintf(output, "</list>\n");
7549 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007550 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007551 fprintf(output, "<oneOrMore>\n");
7552 xmlRelaxNGDumpDefines(output, define->content);
7553 fprintf(output, "</oneOrMore>\n");
7554 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007555 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007556 fprintf(output, "<zeroOrMore>\n");
7557 xmlRelaxNGDumpDefines(output, define->content);
7558 fprintf(output, "</zeroOrMore>\n");
7559 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007560 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007561 fprintf(output, "<choice>\n");
7562 xmlRelaxNGDumpDefines(output, define->content);
7563 fprintf(output, "</choice>\n");
7564 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007565 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007566 fprintf(output, "<group>\n");
7567 xmlRelaxNGDumpDefines(output, define->content);
7568 fprintf(output, "</group>\n");
7569 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007570 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007571 fprintf(output, "<interleave>\n");
7572 xmlRelaxNGDumpDefines(output, define->content);
7573 fprintf(output, "</interleave>\n");
7574 break;
7575 case XML_RELAXNG_OPTIONAL:
7576 fprintf(output, "<optional>\n");
7577 xmlRelaxNGDumpDefines(output, define->content);
7578 fprintf(output, "</optional>\n");
7579 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007580 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007581 fprintf(output, "<attribute>\n");
7582 xmlRelaxNGDumpDefines(output, define->content);
7583 fprintf(output, "</attribute>\n");
7584 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007585 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007586 fprintf(output, "<define");
7587 if (define->name != NULL)
7588 fprintf(output, " name=\"%s\"", define->name);
7589 fprintf(output, ">\n");
7590 xmlRelaxNGDumpDefines(output, define->content);
7591 fprintf(output, "</define>\n");
7592 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007593 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007594 fprintf(output, "<ref");
7595 if (define->name != NULL)
7596 fprintf(output, " name=\"%s\"", define->name);
7597 fprintf(output, ">\n");
7598 xmlRelaxNGDumpDefines(output, define->content);
7599 fprintf(output, "</ref>\n");
7600 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007601 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007602 fprintf(output, "<parentRef");
7603 if (define->name != NULL)
7604 fprintf(output, " name=\"%s\"", define->name);
7605 fprintf(output, ">\n");
7606 xmlRelaxNGDumpDefines(output, define->content);
7607 fprintf(output, "</parentRef>\n");
7608 break;
7609 case XML_RELAXNG_EXTERNALREF:
7610 fprintf(output, "<externalRef>");
7611 xmlRelaxNGDumpDefines(output, define->content);
7612 fprintf(output, "</externalRef>\n");
7613 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007614 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007615 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007616 TODO break;
7617 case XML_RELAXNG_START:
7618 case XML_RELAXNG_EXCEPT:
7619 case XML_RELAXNG_PARAM:
7620 TODO break;
7621 case XML_RELAXNG_NOOP:
7622 xmlRelaxNGDumpDefines(output, define->content);
7623 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007624 }
7625}
Daniel Veillard4c004142003-10-07 11:33:24 +00007626
Daniel Veillard6eadf632003-01-23 18:29:16 +00007627/**
7628 * xmlRelaxNGDumpGrammar:
7629 * @output: the file output
7630 * @grammar: a grammar structure
7631 * @top: is this a top grammar
7632 *
7633 * Dump a RelaxNG structure back
7634 */
7635static void
7636xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7637{
7638 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007639 return;
7640
Daniel Veillard6eadf632003-01-23 18:29:16 +00007641 fprintf(output, "<grammar");
7642 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007643 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7644 switch (grammar->combine) {
7645 case XML_RELAXNG_COMBINE_UNDEFINED:
7646 break;
7647 case XML_RELAXNG_COMBINE_CHOICE:
7648 fprintf(output, " combine=\"choice\"");
7649 break;
7650 case XML_RELAXNG_COMBINE_INTERLEAVE:
7651 fprintf(output, " combine=\"interleave\"");
7652 break;
7653 default:
7654 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007655 }
7656 fprintf(output, ">\n");
7657 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007658 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007659 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007660 fprintf(output, "<start>\n");
7661 xmlRelaxNGDumpDefine(output, grammar->start);
7662 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007663 }
7664 /* TODO ? Dump the defines ? */
7665 fprintf(output, "</grammar>\n");
7666}
7667
7668/**
7669 * xmlRelaxNGDump:
7670 * @output: the file output
7671 * @schema: a schema structure
7672 *
7673 * Dump a RelaxNG structure back
7674 */
7675void
7676xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7677{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007678 if (output == NULL)
7679 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007680 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007681 fprintf(output, "RelaxNG empty or failed to compile\n");
7682 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007683 }
7684 fprintf(output, "RelaxNG: ");
7685 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007686 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007687 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007688 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007689 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007690 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007691 }
7692 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007693 fprintf(output, "RelaxNG has no top grammar\n");
7694 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007695 }
7696 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7697}
7698
Daniel Veillardfebcca42003-02-16 15:44:18 +00007699/**
7700 * xmlRelaxNGDumpTree:
7701 * @output: the file output
7702 * @schema: a schema structure
7703 *
7704 * Dump the transformed RelaxNG tree.
7705 */
7706void
7707xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7708{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007709 if (output == NULL)
7710 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007711 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007712 fprintf(output, "RelaxNG empty or failed to compile\n");
7713 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007714 }
7715 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007716 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007717 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007718 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007719 }
7720}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007721#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007722
Daniel Veillard6eadf632003-01-23 18:29:16 +00007723/************************************************************************
7724 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007725 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007726 * *
7727 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007728static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7729 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007730
7731/**
7732 * xmlRelaxNGValidateCompiledCallback:
7733 * @exec: the regular expression instance
7734 * @token: the token which matched
7735 * @transdata: callback data, the define for the subelement if available
7736 @ @inputdata: callback data, the Relax NG validation context
7737 *
7738 * Handle the callback and if needed validate the element children.
7739 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007740static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007741xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007742 const xmlChar * token,
7743 void *transdata, void *inputdata)
7744{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007745 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7746 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7747 int ret;
7748
7749#ifdef DEBUG_COMPILE
7750 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007751 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007752#endif
7753 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007754 fprintf(stderr, "callback on %s missing context\n", token);
7755 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7756 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7757 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007758 }
7759 if (define == NULL) {
7760 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007761 return;
7762 fprintf(stderr, "callback on %s missing define\n", token);
7763 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7764 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7765 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007766 }
7767 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007768 fprintf(stderr, "callback on %s missing info\n", token);
7769 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7770 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7771 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007772 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007773 fprintf(stderr, "callback on %s define is not element\n", token);
7774 if (ctxt->errNo == XML_RELAXNG_OK)
7775 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7776 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007777 }
7778 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007779 if (ret != 0)
7780 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007781}
7782
7783/**
7784 * xmlRelaxNGValidateCompiledContent:
7785 * @ctxt: the RelaxNG validation context
7786 * @regexp: the regular expression as compiled
7787 * @content: list of children to test against the regexp
7788 *
7789 * Validate the content model of an element or start using the regexp
7790 *
7791 * Returns 0 in case of success, -1 in case of error.
7792 */
7793static int
7794xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007795 xmlRegexpPtr regexp, xmlNodePtr content)
7796{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007797 xmlRegExecCtxtPtr exec;
7798 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007799 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007800 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007801
7802 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007803 return (-1);
7804 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007805 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007806 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007807 cur = content;
7808 while (cur != NULL) {
7809 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007810 switch (cur->type) {
7811 case XML_TEXT_NODE:
7812 case XML_CDATA_SECTION_NODE:
7813 if (xmlIsBlankNode(cur))
7814 break;
7815 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7816 if (ret < 0) {
7817 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7818 cur->parent->name);
7819 }
7820 break;
7821 case XML_ELEMENT_NODE:
7822 if (cur->ns != NULL) {
7823 ret = xmlRegExecPushString2(exec, cur->name,
7824 cur->ns->href, ctxt);
7825 } else {
7826 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7827 }
7828 if (ret < 0) {
7829 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7830 }
7831 break;
7832 default:
7833 break;
7834 }
7835 if (ret < 0)
7836 break;
7837 /*
7838 * Switch to next element
7839 */
7840 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007841 }
7842 ret = xmlRegExecPushString(exec, NULL, NULL);
7843 if (ret == 1) {
7844 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007845 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007846 } else if (ret == 0) {
7847 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007848 * TODO: get some of the names needed to exit the current state of exec
7849 */
7850 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7851 ret = -1;
7852 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7853 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007854 } else {
7855 ret = -1;
7856 }
7857 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007858 /*
7859 * There might be content model errors outside of the pure
7860 * regexp validation, e.g. for attribute values.
7861 */
7862 if ((ret == 0) && (ctxt->perr != 0)) {
7863 ret = ctxt->perr;
7864 }
7865 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007866 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007867}
7868
7869/************************************************************************
7870 * *
7871 * Progressive validation of when possible *
7872 * *
7873 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007874static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7875 xmlRelaxNGDefinePtr defines);
7876static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007877 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007878static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007879
7880/**
7881 * xmlRelaxNGElemPush:
7882 * @ctxt: the validation context
7883 * @exec: the regexp runtime for the new content model
7884 *
7885 * Push a new regexp for the current node content model on the stack
7886 *
7887 * Returns 0 in case of success and -1 in case of error.
7888 */
7889static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007890xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7891{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007892 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007893 ctxt->elemMax = 10;
7894 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7895 sizeof
7896 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007897 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007898 xmlRngVErrMemory(ctxt, "validating\n");
7899 return (-1);
7900 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007901 }
7902 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007903 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007904 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007905 ctxt->elemMax *
7906 sizeof
7907 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007908 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007909 xmlRngVErrMemory(ctxt, "validating\n");
7910 return (-1);
7911 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007912 }
7913 ctxt->elemTab[ctxt->elemNr++] = exec;
7914 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007915 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007916}
7917
7918/**
7919 * xmlRelaxNGElemPop:
7920 * @ctxt: the validation context
7921 *
7922 * Pop the regexp of the current node content model from the stack
7923 *
7924 * Returns the exec or NULL if empty
7925 */
7926static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007927xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7928{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007929 xmlRegExecCtxtPtr ret;
7930
Daniel Veillard4c004142003-10-07 11:33:24 +00007931 if (ctxt->elemNr <= 0)
7932 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007933 ctxt->elemNr--;
7934 ret = ctxt->elemTab[ctxt->elemNr];
7935 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007936 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007937 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7938 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007939 ctxt->elem = NULL;
7940 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007941}
7942
7943/**
7944 * xmlRelaxNGValidateProgressiveCallback:
7945 * @exec: the regular expression instance
7946 * @token: the token which matched
7947 * @transdata: callback data, the define for the subelement if available
7948 @ @inputdata: callback data, the Relax NG validation context
7949 *
7950 * Handle the callback and if needed validate the element children.
7951 * some of the in/out informations are passed via the context in @inputdata.
7952 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007953static void
7954xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7955 ATTRIBUTE_UNUSED,
7956 const xmlChar * token,
7957 void *transdata, void *inputdata)
7958{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007959 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7960 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007961 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007962 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007963 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007964
7965#ifdef DEBUG_PROGRESSIVE
7966 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007967 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007968#endif
7969 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007970 fprintf(stderr, "callback on %s missing context\n", token);
7971 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007972 }
7973 ctxt->pstate = 1;
7974 if (define == NULL) {
7975 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007976 return;
7977 fprintf(stderr, "callback on %s missing define\n", token);
7978 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7979 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7980 ctxt->pstate = -1;
7981 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007982 }
7983 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007984 fprintf(stderr, "callback on %s missing info\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 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007990 fprintf(stderr, "callback on %s define is not element\n", token);
7991 if (ctxt->errNo == XML_RELAXNG_OK)
7992 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7993 ctxt->pstate = -1;
7994 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007995 }
7996 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007997 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7998 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7999 xmlRelaxNGDumpValidError(ctxt);
8000 ctxt->pstate = -1;
8001 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008002 }
8003 if (define->contModel == NULL) {
8004 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008005 * this node cannot be validated in a streamable fashion
8006 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00008007#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008008 xmlGenericError(xmlGenericErrorContext,
8009 "Element '%s' validation is not streamable\n",
8010 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008011#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008012 ctxt->pstate = 0;
8013 ctxt->pdef = define;
8014 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008015 }
8016 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008017 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008018 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008019 ctxt->pstate = -1;
8020 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008021 }
8022 xmlRelaxNGElemPush(ctxt, exec);
8023
8024 /*
8025 * Validate the attributes part of the content.
8026 */
8027 state = xmlRelaxNGNewValidState(ctxt, node);
8028 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008029 ctxt->pstate = -1;
8030 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008031 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008032 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008033 ctxt->state = state;
8034 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008035 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8036 if (ret != 0) {
8037 ctxt->pstate = -1;
8038 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8039 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008040 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008041 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008042 ctxt->state->seq = NULL;
8043 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8044 if (ret != 0) {
8045 ctxt->pstate = -1;
8046 }
8047 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008048 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008049 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008050
8051 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008052
Daniel Veillard4c004142003-10-07 11:33:24 +00008053 for (i = 0; i < ctxt->states->nbState; i++) {
8054 state = ctxt->states->tabState[i];
8055 ctxt->state = state;
8056 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008057
Daniel Veillard4c004142003-10-07 11:33:24 +00008058 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8059 tmp = 0;
8060 break;
8061 }
8062 }
8063 if (tmp != 0) {
8064 /*
8065 * validation error, log the message for the "best" one
8066 */
8067 ctxt->flags |= FLAGS_IGNORABLE;
8068 xmlRelaxNGLogBestError(ctxt);
8069 }
8070 for (i = 0; i < ctxt->states->nbState; i++) {
8071 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8072 }
8073 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8074 ctxt->states = NULL;
8075 if ((ret == 0) && (tmp == -1))
8076 ctxt->pstate = -1;
8077 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008078 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008079 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008080 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8081 xmlRelaxNGDumpValidError(ctxt);
8082 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008083 }
8084 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008085}
8086
8087/**
8088 * xmlRelaxNGValidatePushElement:
8089 * @ctxt: the validation context
8090 * @doc: a document instance
8091 * @elem: an element instance
8092 *
8093 * Push a new element start on the RelaxNG validation stack.
8094 *
8095 * returns 1 if no validation problem was found or 0 if validating the
8096 * element requires a full node, and -1 in case of error.
8097 */
8098int
Daniel Veillard33300b42003-04-17 09:09:19 +00008099xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8100 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008101 xmlNodePtr elem)
8102{
8103 int ret = 1;
8104
8105 if ((ctxt == NULL) || (elem == NULL))
8106 return (-1);
8107
8108#ifdef DEBUG_PROGRESSIVE
8109 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8110#endif
8111 if (ctxt->elem == 0) {
8112 xmlRelaxNGPtr schema;
8113 xmlRelaxNGGrammarPtr grammar;
8114 xmlRegExecCtxtPtr exec;
8115 xmlRelaxNGDefinePtr define;
8116
8117 schema = ctxt->schema;
8118 if (schema == NULL) {
8119 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8120 return (-1);
8121 }
8122 grammar = schema->topgrammar;
8123 if ((grammar == NULL) || (grammar->start == NULL)) {
8124 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8125 return (-1);
8126 }
8127 define = grammar->start;
8128 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008129 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008130 return (0);
8131 }
8132 exec = xmlRegNewExecCtxt(define->contModel,
8133 xmlRelaxNGValidateProgressiveCallback,
8134 ctxt);
8135 if (exec == NULL) {
8136 return (-1);
8137 }
8138 xmlRelaxNGElemPush(ctxt, exec);
8139 }
8140 ctxt->pnode = elem;
8141 ctxt->pstate = 0;
8142 if (elem->ns != NULL) {
8143 ret =
8144 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8145 ctxt);
8146 } else {
8147 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8148 }
8149 if (ret < 0) {
8150 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8151 } else {
8152 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008153 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008154 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008155 ret = -1;
8156 else
8157 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008158 }
8159#ifdef DEBUG_PROGRESSIVE
8160 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008161 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8162 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008163#endif
8164 return (ret);
8165}
8166
8167/**
8168 * xmlRelaxNGValidatePushCData:
8169 * @ctxt: the RelaxNG validation context
8170 * @data: some character data read
8171 * @len: the lenght of the data
8172 *
8173 * check the CData parsed for validation in the current stack
8174 *
8175 * returns 1 if no validation problem was found or -1 otherwise
8176 */
8177int
8178xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008179 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008180{
8181 int ret = 1;
8182
8183 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8184 return (-1);
8185
8186#ifdef DEBUG_PROGRESSIVE
8187 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8188#endif
8189
8190 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008191 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008192 break;
8193 data++;
8194 }
8195 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008196 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008197
8198 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8199 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008200 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008201#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008202 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008203#endif
8204
Daniel Veillard4c004142003-10-07 11:33:24 +00008205 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008206 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008207 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008208}
8209
8210/**
8211 * xmlRelaxNGValidatePopElement:
8212 * @ctxt: the RelaxNG validation context
8213 * @doc: a document instance
8214 * @elem: an element instance
8215 *
8216 * Pop the element end from the RelaxNG validation stack.
8217 *
8218 * returns 1 if no validation problem was found or 0 otherwise
8219 */
8220int
8221xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8222 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008223 xmlNodePtr elem)
8224{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008225 int ret;
8226 xmlRegExecCtxtPtr exec;
8227
Daniel Veillard4c004142003-10-07 11:33:24 +00008228 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8229 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008230#ifdef DEBUG_PROGRESSIVE
8231 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8232#endif
8233 /*
8234 * verify that we reached a terminal state of the content model.
8235 */
8236 exec = xmlRelaxNGElemPop(ctxt);
8237 ret = xmlRegExecPushString(exec, NULL, NULL);
8238 if (ret == 0) {
8239 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008240 * TODO: get some of the names needed to exit the current state of exec
8241 */
8242 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8243 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008244 } else if (ret < 0) {
8245 ret = -1;
8246 } else {
8247 ret = 1;
8248 }
8249 xmlRegFreeExecCtxt(exec);
8250#ifdef DEBUG_PROGRESSIVE
8251 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008252 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8253 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008254#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008255 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008256}
8257
8258/**
8259 * xmlRelaxNGValidateFullElement:
8260 * @ctxt: the validation context
8261 * @doc: a document instance
8262 * @elem: an element instance
8263 *
8264 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8265 * 0 and the content of the node has been expanded.
8266 *
8267 * returns 1 if no validation problem was found or -1 in case of error.
8268 */
8269int
Daniel Veillard33300b42003-04-17 09:09:19 +00008270xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8271 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008272 xmlNodePtr elem)
8273{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008274 int ret;
8275 xmlRelaxNGValidStatePtr state;
8276
Daniel Veillard4c004142003-10-07 11:33:24 +00008277 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8278 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008279#ifdef DEBUG_PROGRESSIVE
8280 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8281#endif
8282 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8283 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008284 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008285 }
8286 state->seq = elem;
8287 ctxt->state = state;
8288 ctxt->errNo = XML_RELAXNG_OK;
8289 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008290 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8291 ret = -1;
8292 else
8293 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008294 xmlRelaxNGFreeValidState(ctxt, state);
8295 ctxt->state = NULL;
8296#ifdef DEBUG_PROGRESSIVE
8297 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008298 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8299 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008300#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008301 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008302}
8303
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008304/************************************************************************
8305 * *
8306 * Generic interpreted validation implementation *
8307 * *
8308 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008309static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8310 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008311
8312/**
8313 * xmlRelaxNGSkipIgnored:
8314 * @ctxt: a schema validation context
8315 * @node: the top node.
8316 *
8317 * Skip ignorable nodes in that context
8318 *
8319 * Returns the new sibling or NULL in case of error.
8320 */
8321static xmlNodePtr
8322xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008323 xmlNodePtr node)
8324{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008325 /*
8326 * TODO complete and handle entities
8327 */
8328 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008329 ((node->type == XML_COMMENT_NODE) ||
8330 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008331 (node->type == XML_XINCLUDE_START) ||
8332 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008333 (((node->type == XML_TEXT_NODE) ||
8334 (node->type == XML_CDATA_SECTION_NODE)) &&
8335 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8336 (IS_BLANK_NODE(node)))))) {
8337 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008338 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008339 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008340}
8341
8342/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008343 * xmlRelaxNGNormalize:
8344 * @ctxt: a schema validation context
8345 * @str: the string to normalize
8346 *
8347 * Implements the normalizeWhiteSpace( s ) function from
8348 * section 6.2.9 of the spec
8349 *
8350 * Returns the new string or NULL in case of error.
8351 */
8352static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008353xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8354{
Daniel Veillardedc91922003-01-26 00:52:04 +00008355 xmlChar *ret, *p;
8356 const xmlChar *tmp;
8357 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008358
Daniel Veillardedc91922003-01-26 00:52:04 +00008359 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008360 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008361 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008362 while (*tmp != 0)
8363 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008364 len = tmp - str;
8365
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008366 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008367 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008368 xmlRngVErrMemory(ctxt, "validating\n");
8369 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008370 }
8371 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008372 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008373 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008374 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008375 if (IS_BLANK_CH(*str)) {
8376 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008377 str++;
8378 if (*str == 0)
8379 break;
8380 *p++ = ' ';
8381 } else
8382 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008383 }
8384 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008385 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008386}
8387
8388/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008389 * xmlRelaxNGValidateDatatype:
8390 * @ctxt: a Relax-NG validation context
8391 * @value: the string value
8392 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008393 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008394 *
8395 * Validate the given value against the dataype
8396 *
8397 * Returns 0 if the validation succeeded or an error code.
8398 */
8399static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008400xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8401 const xmlChar * value,
8402 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8403{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008404 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008405 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008406 void *result = NULL;
8407 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008408
8409 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008410 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008411 }
8412 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008413 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008414 if ((define->attrs != NULL) &&
8415 (define->attrs->type == XML_RELAXNG_PARAM)) {
8416 ret =
8417 lib->check(lib->data, define->name, value, &result, node);
8418 } else {
8419 ret = lib->check(lib->data, define->name, value, NULL, node);
8420 }
8421 } else
8422 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008423 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008424 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8425 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8426 lib->freef(lib->data, result);
8427 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008428 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008429 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008430 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008431 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008432 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008433 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8434 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008435 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008436 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008437 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008438 if (lib->facet != NULL) {
8439 tmp = lib->facet(lib->data, define->name, cur->name,
8440 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008441 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008442 ret = -1;
8443 }
8444 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008445 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008446 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008447 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008448
Daniel Veillard4c004142003-10-07 11:33:24 +00008449 oldvalue = ctxt->state->value;
8450 oldendvalue = ctxt->state->endvalue;
8451 ctxt->state->value = (xmlChar *) value;
8452 ctxt->state->endvalue = NULL;
8453 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8454 ctxt->state->value = (xmlChar *) oldvalue;
8455 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008456 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008457 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008458 lib->freef(lib->data, result);
8459 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008460}
8461
8462/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008463 * xmlRelaxNGNextValue:
8464 * @ctxt: a Relax-NG validation context
8465 *
8466 * Skip to the next value when validating within a list
8467 *
8468 * Returns 0 if the operation succeeded or an error code.
8469 */
8470static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008471xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8472{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008473 xmlChar *cur;
8474
8475 cur = ctxt->state->value;
8476 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008477 ctxt->state->value = NULL;
8478 ctxt->state->endvalue = NULL;
8479 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008480 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008481 while (*cur != 0)
8482 cur++;
8483 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8484 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008485 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008486 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008487 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008488 ctxt->state->value = cur;
8489 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008490}
8491
8492/**
8493 * xmlRelaxNGValidateValueList:
8494 * @ctxt: a Relax-NG validation context
8495 * @defines: the list of definitions to verify
8496 *
8497 * Validate the given set of definitions for the current value
8498 *
8499 * Returns 0 if the validation succeeded or an error code.
8500 */
8501static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008502xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8503 xmlRelaxNGDefinePtr defines)
8504{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008505 int ret = 0;
8506
8507 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008508 ret = xmlRelaxNGValidateValue(ctxt, defines);
8509 if (ret != 0)
8510 break;
8511 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008512 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008513 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008514}
8515
8516/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008517 * xmlRelaxNGValidateValue:
8518 * @ctxt: a Relax-NG validation context
8519 * @define: the definition to verify
8520 *
8521 * Validate the given definition for the current value
8522 *
8523 * Returns 0 if the validation succeeded or an error code.
8524 */
8525static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008526xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8527 xmlRelaxNGDefinePtr define)
8528{
Daniel Veillardedc91922003-01-26 00:52:04 +00008529 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008530 xmlChar *value;
8531
8532 value = ctxt->state->value;
8533 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008534 case XML_RELAXNG_EMPTY:{
8535 if ((value != NULL) && (value[0] != 0)) {
8536 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008537
William M. Brack76e95df2003-10-18 16:20:14 +00008538 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008539 idx++;
8540 if (value[idx] != 0)
8541 ret = -1;
8542 }
8543 break;
8544 }
8545 case XML_RELAXNG_TEXT:
8546 break;
8547 case XML_RELAXNG_VALUE:{
8548 if (!xmlStrEqual(value, define->value)) {
8549 if (define->name != NULL) {
8550 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008551
Daniel Veillard4c004142003-10-07 11:33:24 +00008552 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8553 if ((lib != NULL) && (lib->comp != NULL)) {
8554 ret = lib->comp(lib->data, define->name,
8555 define->value, define->node,
8556 (void *) define->attrs,
8557 value, ctxt->state->node);
8558 } else
8559 ret = -1;
8560 if (ret < 0) {
8561 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8562 define->name);
8563 return (-1);
8564 } else if (ret == 1) {
8565 ret = 0;
8566 } else {
8567 ret = -1;
8568 }
8569 } else {
8570 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008571
Daniel Veillard4c004142003-10-07 11:33:24 +00008572 /*
8573 * TODO: trivial optimizations are possible by
8574 * computing at compile-time
8575 */
8576 nval = xmlRelaxNGNormalize(ctxt, define->value);
8577 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008578
Daniel Veillard4c004142003-10-07 11:33:24 +00008579 if ((nval == NULL) || (nvalue == NULL) ||
8580 (!xmlStrEqual(nval, nvalue)))
8581 ret = -1;
8582 if (nval != NULL)
8583 xmlFree(nval);
8584 if (nvalue != NULL)
8585 xmlFree(nvalue);
8586 }
8587 }
8588 if (ret == 0)
8589 xmlRelaxNGNextValue(ctxt);
8590 break;
8591 }
8592 case XML_RELAXNG_DATATYPE:{
8593 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8594 ctxt->state->seq);
8595 if (ret == 0)
8596 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008597
Daniel Veillard4c004142003-10-07 11:33:24 +00008598 break;
8599 }
8600 case XML_RELAXNG_CHOICE:{
8601 xmlRelaxNGDefinePtr list = define->content;
8602 xmlChar *oldvalue;
8603
8604 oldflags = ctxt->flags;
8605 ctxt->flags |= FLAGS_IGNORABLE;
8606
8607 oldvalue = ctxt->state->value;
8608 while (list != NULL) {
8609 ret = xmlRelaxNGValidateValue(ctxt, list);
8610 if (ret == 0) {
8611 break;
8612 }
8613 ctxt->state->value = oldvalue;
8614 list = list->next;
8615 }
8616 ctxt->flags = oldflags;
8617 if (ret != 0) {
8618 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8619 xmlRelaxNGDumpValidError(ctxt);
8620 } else {
8621 if (ctxt->errNr > 0)
8622 xmlRelaxNGPopErrors(ctxt, 0);
8623 }
8624 if (ret == 0)
8625 xmlRelaxNGNextValue(ctxt);
8626 break;
8627 }
8628 case XML_RELAXNG_LIST:{
8629 xmlRelaxNGDefinePtr list = define->content;
8630 xmlChar *oldvalue, *oldend, *val, *cur;
8631
Daniel Veillard416589a2003-02-17 17:25:42 +00008632#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008633 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008634#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008635
Daniel Veillard4c004142003-10-07 11:33:24 +00008636 oldvalue = ctxt->state->value;
8637 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008638
Daniel Veillard4c004142003-10-07 11:33:24 +00008639 val = xmlStrdup(oldvalue);
8640 if (val == NULL) {
8641 val = xmlStrdup(BAD_CAST "");
8642 }
8643 if (val == NULL) {
8644 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8645 return (-1);
8646 }
8647 cur = val;
8648 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008649 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008650 *cur = 0;
8651 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008652#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008653 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008654#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008655 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008656 *cur++ = 0;
8657 } else
8658 cur++;
8659 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008660#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008661 xmlGenericError(xmlGenericErrorContext,
8662 "list value: '%s' found %d items\n",
8663 oldvalue, nb_values);
8664 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008665#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008666 ctxt->state->endvalue = cur;
8667 cur = val;
8668 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8669 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008670
Daniel Veillard4c004142003-10-07 11:33:24 +00008671 ctxt->state->value = cur;
8672
8673 while (list != NULL) {
8674 if (ctxt->state->value == ctxt->state->endvalue)
8675 ctxt->state->value = NULL;
8676 ret = xmlRelaxNGValidateValue(ctxt, list);
8677 if (ret != 0) {
8678#ifdef DEBUG_LIST
8679 xmlGenericError(xmlGenericErrorContext,
8680 "Failed to validate value: '%s' with %d rule\n",
8681 ctxt->state->value, nb_values);
8682#endif
8683 break;
8684 }
8685#ifdef DEBUG_LIST
8686 nb_values++;
8687#endif
8688 list = list->next;
8689 }
8690
8691 if ((ret == 0) && (ctxt->state->value != NULL) &&
8692 (ctxt->state->value != ctxt->state->endvalue)) {
8693 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8694 ctxt->state->value);
8695 ret = -1;
8696 }
8697 xmlFree(val);
8698 ctxt->state->value = oldvalue;
8699 ctxt->state->endvalue = oldend;
8700 break;
8701 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008702 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008703 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8704 if (ret != 0) {
8705 break;
8706 }
8707 /* no break on purpose */
8708 case XML_RELAXNG_ZEROORMORE:{
8709 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008710
Daniel Veillard4c004142003-10-07 11:33:24 +00008711 oldflags = ctxt->flags;
8712 ctxt->flags |= FLAGS_IGNORABLE;
8713 cur = ctxt->state->value;
8714 temp = NULL;
8715 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8716 (temp != cur)) {
8717 temp = cur;
8718 ret =
8719 xmlRelaxNGValidateValueList(ctxt, define->content);
8720 if (ret != 0) {
8721 ctxt->state->value = temp;
8722 ret = 0;
8723 break;
8724 }
8725 cur = ctxt->state->value;
8726 }
8727 ctxt->flags = oldflags;
8728 if (ret != 0) {
8729 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8730 xmlRelaxNGDumpValidError(ctxt);
8731 } else {
8732 if (ctxt->errNr > 0)
8733 xmlRelaxNGPopErrors(ctxt, 0);
8734 }
8735 break;
8736 }
8737 case XML_RELAXNG_EXCEPT:{
8738 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008739
Daniel Veillard4c004142003-10-07 11:33:24 +00008740 list = define->content;
8741 while (list != NULL) {
8742 ret = xmlRelaxNGValidateValue(ctxt, list);
8743 if (ret == 0) {
8744 ret = -1;
8745 break;
8746 } else
8747 ret = 0;
8748 list = list->next;
8749 }
8750 break;
8751 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008752 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008753 case XML_RELAXNG_GROUP:{
8754 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008755
Daniel Veillard4c004142003-10-07 11:33:24 +00008756 list = define->content;
8757 while (list != NULL) {
8758 ret = xmlRelaxNGValidateValue(ctxt, list);
8759 if (ret != 0) {
8760 ret = -1;
8761 break;
8762 } else
8763 ret = 0;
8764 list = list->next;
8765 }
8766 break;
8767 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008768 case XML_RELAXNG_REF:
8769 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008770 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8771 break;
8772 default:
8773 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008774 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008775 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008776}
8777
8778/**
8779 * xmlRelaxNGValidateValueContent:
8780 * @ctxt: a Relax-NG validation context
8781 * @defines: the list of definitions to verify
8782 *
8783 * Validate the given definitions for the current value
8784 *
8785 * Returns 0 if the validation succeeded or an error code.
8786 */
8787static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008788xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8789 xmlRelaxNGDefinePtr defines)
8790{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008791 int ret = 0;
8792
8793 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008794 ret = xmlRelaxNGValidateValue(ctxt, defines);
8795 if (ret != 0)
8796 break;
8797 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008798 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008799 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008800}
8801
8802/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008803 * xmlRelaxNGAttributeMatch:
8804 * @ctxt: a Relax-NG validation context
8805 * @define: the definition to check
8806 * @prop: the attribute
8807 *
8808 * Check if the attribute matches the definition nameClass
8809 *
8810 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8811 */
8812static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008813xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8814 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8815{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008816 int ret;
8817
8818 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008819 if (!xmlStrEqual(define->name, prop->name))
8820 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008821 }
8822 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008823 if (define->ns[0] == 0) {
8824 if (prop->ns != NULL)
8825 return (0);
8826 } else {
8827 if ((prop->ns == NULL) ||
8828 (!xmlStrEqual(define->ns, prop->ns->href)))
8829 return (0);
8830 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008831 }
8832 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008833 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008834 define = define->nameClass;
8835 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008836 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008837
Daniel Veillard4c004142003-10-07 11:33:24 +00008838 list = define->content;
8839 while (list != NULL) {
8840 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8841 if (ret == 1)
8842 return (0);
8843 if (ret < 0)
8844 return (ret);
8845 list = list->next;
8846 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008847 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008848 TODO}
8849 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008850}
8851
8852/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008853 * xmlRelaxNGValidateAttribute:
8854 * @ctxt: a Relax-NG validation context
8855 * @define: the definition to verify
8856 *
8857 * Validate the given attribute definition for that node
8858 *
8859 * Returns 0 if the validation succeeded or an error code.
8860 */
8861static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008862xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8863 xmlRelaxNGDefinePtr define)
8864{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008865 int ret = 0, i;
8866 xmlChar *value, *oldvalue;
8867 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008868 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008869
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008870 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008871 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008872 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008873 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8874 tmp = ctxt->state->attrs[i];
8875 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8876 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8877 (tmp->ns == NULL)) ||
8878 ((tmp->ns != NULL) &&
8879 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8880 prop = tmp;
8881 break;
8882 }
8883 }
8884 }
8885 if (prop != NULL) {
8886 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8887 oldvalue = ctxt->state->value;
8888 oldseq = ctxt->state->seq;
8889 ctxt->state->seq = (xmlNodePtr) prop;
8890 ctxt->state->value = value;
8891 ctxt->state->endvalue = NULL;
8892 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8893 if (ctxt->state->value != NULL)
8894 value = ctxt->state->value;
8895 if (value != NULL)
8896 xmlFree(value);
8897 ctxt->state->value = oldvalue;
8898 ctxt->state->seq = oldseq;
8899 if (ret == 0) {
8900 /*
8901 * flag the attribute as processed
8902 */
8903 ctxt->state->attrs[i] = NULL;
8904 ctxt->state->nbAttrLeft--;
8905 }
8906 } else {
8907 ret = -1;
8908 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008909#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008910 xmlGenericError(xmlGenericErrorContext,
8911 "xmlRelaxNGValidateAttribute(%s): %d\n",
8912 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008913#endif
8914 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008915 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8916 tmp = ctxt->state->attrs[i];
8917 if ((tmp != NULL) &&
8918 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8919 prop = tmp;
8920 break;
8921 }
8922 }
8923 if (prop != NULL) {
8924 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8925 oldvalue = ctxt->state->value;
8926 oldseq = ctxt->state->seq;
8927 ctxt->state->seq = (xmlNodePtr) prop;
8928 ctxt->state->value = value;
8929 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8930 if (ctxt->state->value != NULL)
8931 value = ctxt->state->value;
8932 if (value != NULL)
8933 xmlFree(value);
8934 ctxt->state->value = oldvalue;
8935 ctxt->state->seq = oldseq;
8936 if (ret == 0) {
8937 /*
8938 * flag the attribute as processed
8939 */
8940 ctxt->state->attrs[i] = NULL;
8941 ctxt->state->nbAttrLeft--;
8942 }
8943 } else {
8944 ret = -1;
8945 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008946#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008947 if (define->ns != NULL) {
8948 xmlGenericError(xmlGenericErrorContext,
8949 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8950 define->ns, ret);
8951 } else {
8952 xmlGenericError(xmlGenericErrorContext,
8953 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8954 ret);
8955 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008956#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008957 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008958
8959 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008960}
8961
8962/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008963 * xmlRelaxNGValidateAttributeList:
8964 * @ctxt: a Relax-NG validation context
8965 * @define: the list of definition to verify
8966 *
8967 * Validate the given node against the list of attribute definitions
8968 *
8969 * Returns 0 if the validation succeeded or an error code.
8970 */
8971static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008972xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8973 xmlRelaxNGDefinePtr defines)
8974{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008975 int ret = 0, res;
8976 int needmore = 0;
8977 xmlRelaxNGDefinePtr cur;
8978
8979 cur = defines;
8980 while (cur != NULL) {
8981 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008982 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8983 ret = -1;
8984 } else
8985 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008986 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008987 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008988 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00008989 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008990 cur = defines;
8991 while (cur != NULL) {
8992 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008993 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8994 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8995 if (res < 0)
8996 ret = -1;
8997 } else {
8998 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8999 return (-1);
9000 }
9001 if (res == -1) /* continues on -2 */
9002 break;
9003 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009004 cur = cur->next;
9005 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009006
9007 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009008}
9009
9010/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009011 * xmlRelaxNGNodeMatchesList:
9012 * @node: the node
9013 * @list: a NULL terminated array of definitions
9014 *
9015 * Check if a node can be matched by one of the definitions
9016 *
9017 * Returns 1 if matches 0 otherwise
9018 */
9019static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009020xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9021{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009022 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009023 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009024
9025 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009026 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009027
9028 cur = list[i++];
9029 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009030 if ((node->type == XML_ELEMENT_NODE) &&
9031 (cur->type == XML_RELAXNG_ELEMENT)) {
9032 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9033 if (tmp == 1)
9034 return (1);
9035 } else if (((node->type == XML_TEXT_NODE) ||
9036 (node->type == XML_CDATA_SECTION_NODE)) &&
9037 (cur->type == XML_RELAXNG_TEXT)) {
9038 return (1);
9039 }
9040 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009041 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009042 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009043}
9044
9045/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009046 * xmlRelaxNGValidateInterleave:
9047 * @ctxt: a Relax-NG validation context
9048 * @define: the definition to verify
9049 *
9050 * Validate an interleave definition for a node.
9051 *
9052 * Returns 0 if the validation succeeded or an error code.
9053 */
9054static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009055xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9056 xmlRelaxNGDefinePtr define)
9057{
William M. Brack779af002003-08-01 15:55:39 +00009058 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009059 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009060 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009061
9062 xmlRelaxNGValidStatePtr oldstate;
9063 xmlRelaxNGPartitionPtr partitions;
9064 xmlRelaxNGInterleaveGroupPtr group = NULL;
9065 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9066 xmlNodePtr *list = NULL, *lasts = NULL;
9067
9068 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009069 partitions = (xmlRelaxNGPartitionPtr) define->data;
9070 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009071 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009072 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9073 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009074 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009075 /*
9076 * Optimizations for MIXED
9077 */
9078 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009079 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009080 ctxt->flags |= FLAGS_MIXED_CONTENT;
9081 if (nbgroups == 2) {
9082 /*
9083 * this is a pure <mixed> case
9084 */
9085 if (ctxt->state != NULL)
9086 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9087 ctxt->state->seq);
9088 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9089 ret = xmlRelaxNGValidateDefinition(ctxt,
9090 partitions->groups[1]->
9091 rule);
9092 else
9093 ret = xmlRelaxNGValidateDefinition(ctxt,
9094 partitions->groups[0]->
9095 rule);
9096 if (ret == 0) {
9097 if (ctxt->state != NULL)
9098 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9099 ctxt->state->
9100 seq);
9101 }
9102 ctxt->flags = oldflags;
9103 return (ret);
9104 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009105 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009106
9107 /*
9108 * Build arrays to store the first and last node of the chain
9109 * pertaining to each group
9110 */
9111 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9112 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009113 xmlRngVErrMemory(ctxt, "validating\n");
9114 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009115 }
9116 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9117 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9118 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009119 xmlRngVErrMemory(ctxt, "validating\n");
9120 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009121 }
9122 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9123
9124 /*
9125 * Walk the sequence of children finding the right group and
9126 * sorting them in sequences.
9127 */
9128 cur = ctxt->state->seq;
9129 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9130 start = cur;
9131 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009132 ctxt->state->seq = cur;
9133 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009134 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009135 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009136
Daniel Veillard4c004142003-10-07 11:33:24 +00009137 if ((cur->type == XML_TEXT_NODE) ||
9138 (cur->type == XML_CDATA_SECTION_NODE)) {
9139 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9140 NULL);
9141 } else if (cur->type == XML_ELEMENT_NODE) {
9142 if (cur->ns != NULL) {
9143 tmp = xmlHashLookup2(partitions->triage, cur->name,
9144 cur->ns->href);
9145 if (tmp == NULL)
9146 tmp = xmlHashLookup2(partitions->triage,
9147 BAD_CAST "#any",
9148 cur->ns->href);
9149 } else
9150 tmp =
9151 xmlHashLookup2(partitions->triage, cur->name,
9152 NULL);
9153 if (tmp == NULL)
9154 tmp =
9155 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9156 NULL);
9157 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009158
Daniel Veillard4c004142003-10-07 11:33:24 +00009159 if (tmp == NULL) {
9160 i = nbgroups;
9161 } else {
9162 i = ((long) tmp) - 1;
9163 if (partitions->flags & IS_NEEDCHECK) {
9164 group = partitions->groups[i];
9165 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9166 i = nbgroups;
9167 }
9168 }
9169 } else {
9170 for (i = 0; i < nbgroups; i++) {
9171 group = partitions->groups[i];
9172 if (group == NULL)
9173 continue;
9174 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9175 break;
9176 }
9177 }
9178 /*
9179 * We break as soon as an element not matched is found
9180 */
9181 if (i >= nbgroups) {
9182 break;
9183 }
9184 if (lasts[i] != NULL) {
9185 lasts[i]->next = cur;
9186 lasts[i] = cur;
9187 } else {
9188 list[i] = cur;
9189 lasts[i] = cur;
9190 }
9191 if (cur->next != NULL)
9192 lastchg = cur->next;
9193 else
9194 lastchg = cur;
9195 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009196 }
9197 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009198 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9199 ret = -1;
9200 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009201 }
9202 lastelem = cur;
9203 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009204 for (i = 0; i < nbgroups; i++) {
9205 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9206 group = partitions->groups[i];
9207 if (lasts[i] != NULL) {
9208 last = lasts[i]->next;
9209 lasts[i]->next = NULL;
9210 }
9211 ctxt->state->seq = list[i];
9212 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9213 if (ret != 0)
9214 break;
9215 if (ctxt->state != NULL) {
9216 cur = ctxt->state->seq;
9217 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9218 xmlRelaxNGFreeValidState(ctxt, oldstate);
9219 oldstate = ctxt->state;
9220 ctxt->state = NULL;
9221 if (cur != NULL) {
9222 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9223 ret = -1;
9224 ctxt->state = oldstate;
9225 goto done;
9226 }
9227 } else if (ctxt->states != NULL) {
9228 int j;
9229 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009230
Daniel Veillard4c004142003-10-07 11:33:24 +00009231 for (j = 0; j < ctxt->states->nbState; j++) {
9232 cur = ctxt->states->tabState[j]->seq;
9233 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9234 if (cur == NULL) {
9235 found = 1;
9236 break;
9237 }
9238 }
9239 if (ctxt->states->nbState > 0) {
9240 xmlRelaxNGFreeValidState(ctxt, oldstate);
9241 oldstate =
9242 ctxt->states->tabState[ctxt->states->nbState - 1];
9243 }
9244 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9245 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9246 }
9247 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9248 ctxt->states = NULL;
9249 if (found == 0) {
9250 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9251 ret = -1;
9252 ctxt->state = oldstate;
9253 goto done;
9254 }
9255 } else {
9256 ret = -1;
9257 break;
9258 }
9259 if (lasts[i] != NULL) {
9260 lasts[i]->next = last;
9261 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009262 }
9263 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009264 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009265 ctxt->state = oldstate;
9266 ctxt->state->seq = lastelem;
9267 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009268 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9269 ret = -1;
9270 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009271 }
9272
Daniel Veillard4c004142003-10-07 11:33:24 +00009273 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009274 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009275 /*
9276 * builds the next links chain from the prev one
9277 */
9278 cur = lastchg;
9279 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009280 if ((cur == start) || (cur->prev == NULL))
9281 break;
9282 cur->prev->next = cur;
9283 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009284 }
9285 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009286 if (ctxt->errNr > errNr)
9287 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009288 }
9289
9290 xmlFree(list);
9291 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009292 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009293}
9294
9295/**
9296 * xmlRelaxNGValidateDefinitionList:
9297 * @ctxt: a Relax-NG validation context
9298 * @define: the list of definition to verify
9299 *
9300 * Validate the given node content against the (list) of definitions
9301 *
9302 * Returns 0 if the validation succeeded or an error code.
9303 */
9304static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009305xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9306 xmlRelaxNGDefinePtr defines)
9307{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009308 int ret = 0, res;
9309
9310
Daniel Veillard952379b2003-03-17 15:37:12 +00009311 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009312 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9313 BAD_CAST "NULL definition list");
9314 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009315 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009316 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009317 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9318 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9319 if (res < 0)
9320 ret = -1;
9321 } else {
9322 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9323 return (-1);
9324 }
9325 if (res == -1) /* continues on -2 */
9326 break;
9327 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009328 }
9329
Daniel Veillard4c004142003-10-07 11:33:24 +00009330 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009331}
9332
9333/**
9334 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009335 * @ctxt: a Relax-NG validation context
9336 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009337 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009338 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009339 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009340 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009341 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009342 */
9343static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009344xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9345 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9346{
Daniel Veillard580ced82003-03-21 21:22:48 +00009347 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009348
Daniel Veillardfd573f12003-03-16 17:52:32 +00009349 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009350 if (!xmlStrEqual(elem->name, define->name)) {
9351 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9352 return (0);
9353 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009354 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009355 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009356 if (elem->ns == NULL) {
9357 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9358 return (0);
9359 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9360 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9361 elem->name, define->ns);
9362 return (0);
9363 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009364 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009365 (define->name == NULL)) {
9366 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9367 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009368 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009369 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9370 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009371 }
9372
9373 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009374 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009375
9376 define = define->nameClass;
9377 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009378 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009379
Daniel Veillard4c004142003-10-07 11:33:24 +00009380 if (ctxt != NULL) {
9381 oldflags = ctxt->flags;
9382 ctxt->flags |= FLAGS_IGNORABLE;
9383 }
9384
9385 list = define->content;
9386 while (list != NULL) {
9387 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9388 if (ret == 1) {
9389 if (ctxt != NULL)
9390 ctxt->flags = oldflags;
9391 return (0);
9392 }
9393 if (ret < 0) {
9394 if (ctxt != NULL)
9395 ctxt->flags = oldflags;
9396 return (ret);
9397 }
9398 list = list->next;
9399 }
9400 ret = 1;
9401 if (ctxt != NULL) {
9402 ctxt->flags = oldflags;
9403 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009404 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009405 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009406
Daniel Veillard4c004142003-10-07 11:33:24 +00009407 if (ctxt != NULL) {
9408 oldflags = ctxt->flags;
9409 ctxt->flags |= FLAGS_IGNORABLE;
9410 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009411
Daniel Veillard4c004142003-10-07 11:33:24 +00009412 list = define->nameClass;
9413 while (list != NULL) {
9414 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9415 if (ret == 1) {
9416 if (ctxt != NULL)
9417 ctxt->flags = oldflags;
9418 return (1);
9419 }
9420 if (ret < 0) {
9421 if (ctxt != NULL)
9422 ctxt->flags = oldflags;
9423 return (ret);
9424 }
9425 list = list->next;
9426 }
9427 if (ctxt != NULL) {
9428 if (ret != 0) {
9429 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9430 xmlRelaxNGDumpValidError(ctxt);
9431 } else {
9432 if (ctxt->errNr > 0)
9433 xmlRelaxNGPopErrors(ctxt, 0);
9434 }
9435 }
9436 ret = 0;
9437 if (ctxt != NULL) {
9438 ctxt->flags = oldflags;
9439 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009440 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009441 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009442 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009443 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009444}
9445
9446/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009447 * xmlRelaxNGBestState:
9448 * @ctxt: a Relax-NG validation context
9449 *
9450 * Find the "best" state in the ctxt->states list of states to report
9451 * errors about. I.e. a state with no element left in the child list
9452 * or the one with the less attributes left.
9453 * This is called only if a falidation error was detected
9454 *
9455 * Returns the index of the "best" state or -1 in case of error
9456 */
9457static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009458xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9459{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009460 xmlRelaxNGValidStatePtr state;
9461 int i, tmp;
9462 int best = -1;
9463 int value = 1000000;
9464
9465 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9466 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009467 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009468
Daniel Veillard4c004142003-10-07 11:33:24 +00009469 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009470 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009471 if (state == NULL)
9472 continue;
9473 if (state->seq != NULL) {
9474 if ((best == -1) || (value > 100000)) {
9475 value = 100000;
9476 best = i;
9477 }
9478 } else {
9479 tmp = state->nbAttrLeft;
9480 if ((best == -1) || (value > tmp)) {
9481 value = tmp;
9482 best = i;
9483 }
9484 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009485 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009486 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009487}
9488
9489/**
9490 * xmlRelaxNGLogBestError:
9491 * @ctxt: a Relax-NG validation context
9492 *
9493 * Find the "best" state in the ctxt->states list of states to report
9494 * errors about and log it.
9495 */
9496static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009497xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9498{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009499 int best;
9500
9501 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9502 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009503 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009504
9505 best = xmlRelaxNGBestState(ctxt);
9506 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009507 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009508
Daniel Veillard4c004142003-10-07 11:33:24 +00009509 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009510 }
9511}
9512
9513/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009514 * xmlRelaxNGValidateElementEnd:
9515 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009516 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009517 *
9518 * Validate the end of the element, implements check that
9519 * there is nothing left not consumed in the element content
9520 * or in the attribute list.
9521 *
9522 * Returns 0 if the validation succeeded or an error code.
9523 */
9524static int
William M. Brack272693c2003-11-14 16:20:34 +00009525xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009526{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009527 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009528 xmlRelaxNGValidStatePtr state;
9529
9530 state = ctxt->state;
9531 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009532 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9533 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009534 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009535 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9536 state->node->name, state->seq->name);
9537 }
9538 return (-1);
9539 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009540 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009541 for (i = 0; i < state->nbAttrs; i++) {
9542 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009543 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009544 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9545 state->attrs[i]->name, state->node->name);
9546 }
9547 return (-1 - i);
9548 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009549 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009550 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009551}
9552
9553/**
9554 * xmlRelaxNGValidateState:
9555 * @ctxt: a Relax-NG validation context
9556 * @define: the definition to verify
9557 *
9558 * Validate the current state against the definition
9559 *
9560 * Returns 0 if the validation succeeded or an error code.
9561 */
9562static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009563xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9564 xmlRelaxNGDefinePtr define)
9565{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009566 xmlNodePtr node;
9567 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009568 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009569
9570 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009571 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9572 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009573 }
9574
9575 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009576 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009577 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009578 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009579 }
9580#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009581 for (i = 0; i < ctxt->depth; i++)
9582 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009583 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009584 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009585 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009586 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009587 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009588 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009589 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009590 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009591#endif
9592 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009593 switch (define->type) {
9594 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009595 node = xmlRelaxNGSkipIgnored(ctxt, node);
9596 ret = 0;
9597 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009598 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009599 ret = -1;
9600 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009601 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009602 while ((node != NULL) &&
9603 ((node->type == XML_TEXT_NODE) ||
9604 (node->type == XML_COMMENT_NODE) ||
9605 (node->type == XML_PI_NODE) ||
9606 (node->type == XML_CDATA_SECTION_NODE)))
9607 node = node->next;
9608 ctxt->state->seq = node;
9609 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009610 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009611 errNr = ctxt->errNr;
9612 node = xmlRelaxNGSkipIgnored(ctxt, node);
9613 if (node == NULL) {
9614 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9615 ret = -1;
9616 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9617 xmlRelaxNGDumpValidError(ctxt);
9618 break;
9619 }
9620 if (node->type != XML_ELEMENT_NODE) {
9621 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9622 ret = -1;
9623 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9624 xmlRelaxNGDumpValidError(ctxt);
9625 break;
9626 }
9627 /*
9628 * This node was already validated successfully against
9629 * this definition.
9630 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009631 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009632 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9633 if (ctxt->errNr > errNr)
9634 xmlRelaxNGPopErrors(ctxt, errNr);
9635 if (ctxt->errNr != 0) {
9636 while ((ctxt->err != NULL) &&
9637 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9638 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9639 ||
9640 ((ctxt->err->err ==
9641 XML_RELAXNG_ERR_ELEMEXTRANS)
9642 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9643 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9644 || (ctxt->err->err ==
9645 XML_RELAXNG_ERR_NOTELEM)))
9646 xmlRelaxNGValidErrorPop(ctxt);
9647 }
9648 break;
9649 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009650
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009651 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9652 if (ret <= 0) {
9653 ret = -1;
9654 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9655 xmlRelaxNGDumpValidError(ctxt);
9656 break;
9657 }
9658 ret = 0;
9659 if (ctxt->errNr != 0) {
9660 if (ctxt->errNr > errNr)
9661 xmlRelaxNGPopErrors(ctxt, errNr);
9662 while ((ctxt->err != NULL) &&
9663 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9664 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9665 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9666 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9667 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9668 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9669 xmlRelaxNGValidErrorPop(ctxt);
9670 }
9671 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009672
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009673 oldflags = ctxt->flags;
9674 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9675 ctxt->flags -= FLAGS_MIXED_CONTENT;
9676 }
9677 state = xmlRelaxNGNewValidState(ctxt, node);
9678 if (state == NULL) {
9679 ret = -1;
9680 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9681 xmlRelaxNGDumpValidError(ctxt);
9682 break;
9683 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009684
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009685 oldstate = ctxt->state;
9686 ctxt->state = state;
9687 if (define->attrs != NULL) {
9688 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9689 if (tmp != 0) {
9690 ret = -1;
9691 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9692 }
9693 }
9694 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009695 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9696 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9697 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009698
Daniel Veillard4c004142003-10-07 11:33:24 +00009699 nstate = xmlRelaxNGNewValidState(ctxt, node);
9700 ctxt->state = nstate;
9701 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009702
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009703 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9704 define->contModel,
9705 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009706 nseq = ctxt->state->seq;
9707 ctxt->state = tmpstate;
9708 ctxt->states = tmpstates;
9709 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009710
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009711#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009712 xmlGenericError(xmlGenericErrorContext,
9713 "Validating content of '%s' : %d\n",
9714 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009715#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009716 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009717 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009718
9719 if (ctxt->states != NULL) {
9720 tmp = -1;
9721
Daniel Veillardce192eb2003-04-16 15:58:05 +00009722 for (i = 0; i < ctxt->states->nbState; i++) {
9723 state = ctxt->states->tabState[i];
9724 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009725 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009726
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009727 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009728 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009729 break;
9730 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009731 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009732 if (tmp != 0) {
9733 /*
9734 * validation error, log the message for the "best" one
9735 */
9736 ctxt->flags |= FLAGS_IGNORABLE;
9737 xmlRelaxNGLogBestError(ctxt);
9738 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009739 for (i = 0; i < ctxt->states->nbState; i++) {
9740 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009741 ctxt->states->
9742 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009743 }
9744 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9745 ctxt->flags = oldflags;
9746 ctxt->states = NULL;
9747 if ((ret == 0) && (tmp == -1))
9748 ret = -1;
9749 } else {
9750 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009751 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009752 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009753 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009754 xmlRelaxNGFreeValidState(ctxt, state);
9755 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009756 } else {
9757 if (define->content != NULL) {
9758 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009759 define->
9760 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009761 if (tmp != 0) {
9762 ret = -1;
9763 if (ctxt->state == NULL) {
9764 ctxt->state = oldstate;
9765 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9766 node->name);
9767 ctxt->state = NULL;
9768 } else {
9769 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9770 node->name);
9771 }
9772
9773 }
9774 }
9775 if (ctxt->states != NULL) {
9776 tmp = -1;
9777
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009778 for (i = 0; i < ctxt->states->nbState; i++) {
9779 state = ctxt->states->tabState[i];
9780 ctxt->state = state;
9781
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009782 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009783 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009784 break;
9785 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009786 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009787 if (tmp != 0) {
9788 /*
9789 * validation error, log the message for the "best" one
9790 */
9791 ctxt->flags |= FLAGS_IGNORABLE;
9792 xmlRelaxNGLogBestError(ctxt);
9793 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009794 for (i = 0; i < ctxt->states->nbState; i++) {
9795 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009796 ctxt->states->
9797 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009798 }
9799 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9800 ctxt->flags = oldflags;
9801 ctxt->states = NULL;
9802 if ((ret == 0) && (tmp == -1))
9803 ret = -1;
9804 } else {
9805 state = ctxt->state;
9806 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009807 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009808 xmlRelaxNGFreeValidState(ctxt, state);
9809 }
9810 }
9811 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009812 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009813 }
9814 ctxt->flags = oldflags;
9815 ctxt->state = oldstate;
9816 if (oldstate != NULL)
9817 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9818 if (ret != 0) {
9819 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9820 xmlRelaxNGDumpValidError(ctxt);
9821 ret = 0;
9822 } else {
9823 ret = -2;
9824 }
9825 } else {
9826 if (ctxt->errNr > errNr)
9827 xmlRelaxNGPopErrors(ctxt, errNr);
9828 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009829
9830#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009831 xmlGenericError(xmlGenericErrorContext,
9832 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9833 node->name, ret);
9834 if (oldstate == NULL)
9835 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9836 else if (oldstate->seq == NULL)
9837 xmlGenericError(xmlGenericErrorContext, ": done\n");
9838 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9839 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9840 oldstate->seq->name);
9841 else
9842 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9843 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009844#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009845 break;
9846 case XML_RELAXNG_OPTIONAL:{
9847 errNr = ctxt->errNr;
9848 oldflags = ctxt->flags;
9849 ctxt->flags |= FLAGS_IGNORABLE;
9850 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9851 ret =
9852 xmlRelaxNGValidateDefinitionList(ctxt,
9853 define->content);
9854 if (ret != 0) {
9855 if (ctxt->state != NULL)
9856 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9857 ctxt->state = oldstate;
9858 ctxt->flags = oldflags;
9859 ret = 0;
9860 if (ctxt->errNr > errNr)
9861 xmlRelaxNGPopErrors(ctxt, errNr);
9862 break;
9863 }
9864 if (ctxt->states != NULL) {
9865 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9866 } else {
9867 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9868 if (ctxt->states == NULL) {
9869 xmlRelaxNGFreeValidState(ctxt, oldstate);
9870 ctxt->flags = oldflags;
9871 ret = -1;
9872 if (ctxt->errNr > errNr)
9873 xmlRelaxNGPopErrors(ctxt, errNr);
9874 break;
9875 }
9876 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9877 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9878 ctxt->state = NULL;
9879 }
9880 ctxt->flags = oldflags;
9881 ret = 0;
9882 if (ctxt->errNr > errNr)
9883 xmlRelaxNGPopErrors(ctxt, errNr);
9884 break;
9885 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009886 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009887 errNr = ctxt->errNr;
9888 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9889 if (ret != 0) {
9890 break;
9891 }
9892 if (ctxt->errNr > errNr)
9893 xmlRelaxNGPopErrors(ctxt, errNr);
9894 /* no break on purpose */
9895 case XML_RELAXNG_ZEROORMORE:{
9896 int progress;
9897 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9898 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009899
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009900 errNr = ctxt->errNr;
9901 res = xmlRelaxNGNewStates(ctxt, 1);
9902 if (res == NULL) {
9903 ret = -1;
9904 break;
9905 }
9906 /*
9907 * All the input states are also exit states
9908 */
9909 if (ctxt->state != NULL) {
9910 xmlRelaxNGAddStates(ctxt, res,
9911 xmlRelaxNGCopyValidState(ctxt,
9912 ctxt->
9913 state));
9914 } else {
9915 for (j = 0; j < ctxt->states->nbState; j++) {
9916 xmlRelaxNGAddStates(ctxt, res,
9917 xmlRelaxNGCopyValidState(ctxt,
9918 ctxt->
9919 states->
9920 tabState
9921 [j]));
9922 }
9923 }
9924 oldflags = ctxt->flags;
9925 ctxt->flags |= FLAGS_IGNORABLE;
9926 do {
9927 progress = 0;
9928 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009929
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009930 if (ctxt->states != NULL) {
9931 states = ctxt->states;
9932 for (i = 0; i < states->nbState; i++) {
9933 ctxt->state = states->tabState[i];
9934 ctxt->states = NULL;
9935 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9936 define->
9937 content);
9938 if (ret == 0) {
9939 if (ctxt->state != NULL) {
9940 tmp = xmlRelaxNGAddStates(ctxt, res,
9941 ctxt->state);
9942 ctxt->state = NULL;
9943 if (tmp == 1)
9944 progress = 1;
9945 } else if (ctxt->states != NULL) {
9946 for (j = 0; j < ctxt->states->nbState;
9947 j++) {
9948 tmp =
9949 xmlRelaxNGAddStates(ctxt, res,
9950 ctxt->
9951 states->
9952 tabState
9953 [j]);
9954 if (tmp == 1)
9955 progress = 1;
9956 }
9957 xmlRelaxNGFreeStates(ctxt,
9958 ctxt->states);
9959 ctxt->states = NULL;
9960 }
9961 } else {
9962 if (ctxt->state != NULL) {
9963 xmlRelaxNGFreeValidState(ctxt,
9964 ctxt->state);
9965 ctxt->state = NULL;
9966 }
9967 }
9968 }
9969 } else {
9970 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9971 define->
9972 content);
9973 if (ret != 0) {
9974 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9975 ctxt->state = NULL;
9976 } else {
9977 base = res->nbState;
9978 if (ctxt->state != NULL) {
9979 tmp = xmlRelaxNGAddStates(ctxt, res,
9980 ctxt->state);
9981 ctxt->state = NULL;
9982 if (tmp == 1)
9983 progress = 1;
9984 } else if (ctxt->states != NULL) {
9985 for (j = 0; j < ctxt->states->nbState; j++) {
9986 tmp = xmlRelaxNGAddStates(ctxt, res,
9987 ctxt->
9988 states->
9989 tabState[j]);
9990 if (tmp == 1)
9991 progress = 1;
9992 }
9993 if (states == NULL) {
9994 states = ctxt->states;
9995 } else {
9996 xmlRelaxNGFreeStates(ctxt,
9997 ctxt->states);
9998 }
9999 ctxt->states = NULL;
10000 }
10001 }
10002 }
10003 if (progress) {
10004 /*
10005 * Collect all the new nodes added at that step
10006 * and make them the new node set
10007 */
10008 if (res->nbState - base == 1) {
10009 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10010 res->
10011 tabState
10012 [base]);
10013 } else {
10014 if (states == NULL) {
10015 xmlRelaxNGNewStates(ctxt,
10016 res->nbState - base);
10017 }
10018 states->nbState = 0;
10019 for (i = base; i < res->nbState; i++)
10020 xmlRelaxNGAddStates(ctxt, states,
10021 xmlRelaxNGCopyValidState
10022 (ctxt,
10023 res->tabState[i]));
10024 ctxt->states = states;
10025 }
10026 }
10027 } while (progress == 1);
10028 if (states != NULL) {
10029 xmlRelaxNGFreeStates(ctxt, states);
10030 }
10031 ctxt->states = res;
10032 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010033#if 0
10034 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010035 * errors may have to be propagated back...
10036 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010037 if (ctxt->errNr > errNr)
10038 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010039#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010040 ret = 0;
10041 break;
10042 }
10043 case XML_RELAXNG_CHOICE:{
10044 xmlRelaxNGDefinePtr list = NULL;
10045 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010046
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010047 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010048
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010049 errNr = ctxt->errNr;
10050 if ((define->dflags & IS_TRIABLE)
10051 && (define->data != NULL)) {
10052 xmlHashTablePtr triage =
10053 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010054
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010055 /*
10056 * Something we can optimize cleanly there is only one
10057 * possble branch out !
10058 */
10059 if (node == NULL) {
10060 ret = -1;
10061 break;
10062 }
10063 if ((node->type == XML_TEXT_NODE) ||
10064 (node->type == XML_CDATA_SECTION_NODE)) {
10065 list =
10066 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10067 } else if (node->type == XML_ELEMENT_NODE) {
10068 if (node->ns != NULL) {
10069 list = xmlHashLookup2(triage, node->name,
10070 node->ns->href);
10071 if (list == NULL)
10072 list =
10073 xmlHashLookup2(triage, BAD_CAST "#any",
10074 node->ns->href);
10075 } else
10076 list =
10077 xmlHashLookup2(triage, node->name, NULL);
10078 if (list == NULL)
10079 list =
10080 xmlHashLookup2(triage, BAD_CAST "#any",
10081 NULL);
10082 }
10083 if (list == NULL) {
10084 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010085 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010086 break;
10087 }
10088 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10089 if (ret == 0) {
10090 }
10091 break;
10092 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010093
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010094 list = define->content;
10095 oldflags = ctxt->flags;
10096 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010097
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010098 while (list != NULL) {
10099 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10100 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10101 if (ret == 0) {
10102 if (states == NULL) {
10103 states = xmlRelaxNGNewStates(ctxt, 1);
10104 }
10105 if (ctxt->state != NULL) {
10106 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10107 } else if (ctxt->states != NULL) {
10108 for (i = 0; i < ctxt->states->nbState; i++) {
10109 xmlRelaxNGAddStates(ctxt, states,
10110 ctxt->states->
10111 tabState[i]);
10112 }
10113 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10114 ctxt->states = NULL;
10115 }
10116 } else {
10117 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10118 }
10119 ctxt->state = oldstate;
10120 list = list->next;
10121 }
10122 if (states != NULL) {
10123 xmlRelaxNGFreeValidState(ctxt, oldstate);
10124 ctxt->states = states;
10125 ctxt->state = NULL;
10126 ret = 0;
10127 } else {
10128 ctxt->states = NULL;
10129 }
10130 ctxt->flags = oldflags;
10131 if (ret != 0) {
10132 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10133 xmlRelaxNGDumpValidError(ctxt);
10134 }
10135 } else {
10136 if (ctxt->errNr > errNr)
10137 xmlRelaxNGPopErrors(ctxt, errNr);
10138 }
10139 break;
10140 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010141 case XML_RELAXNG_DEF:
10142 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010143 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10144 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010145 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010146 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10147 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010148 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010149 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10150 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010151 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010152 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010153 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010154 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010155 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010156 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10157 break;
10158 case XML_RELAXNG_DATATYPE:{
10159 xmlNodePtr child;
10160 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010161
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010162 child = node;
10163 while (child != NULL) {
10164 if (child->type == XML_ELEMENT_NODE) {
10165 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10166 node->parent->name);
10167 ret = -1;
10168 break;
10169 } else if ((child->type == XML_TEXT_NODE) ||
10170 (child->type == XML_CDATA_SECTION_NODE)) {
10171 content = xmlStrcat(content, child->content);
10172 }
10173 /* TODO: handle entities ... */
10174 child = child->next;
10175 }
10176 if (ret == -1) {
10177 if (content != NULL)
10178 xmlFree(content);
10179 break;
10180 }
10181 if (content == NULL) {
10182 content = xmlStrdup(BAD_CAST "");
10183 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010184 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010185 ret = -1;
10186 break;
10187 }
10188 }
10189 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10190 ctxt->state->seq);
10191 if (ret == -1) {
10192 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10193 } else if (ret == 0) {
10194 ctxt->state->seq = NULL;
10195 }
10196 if (content != NULL)
10197 xmlFree(content);
10198 break;
10199 }
10200 case XML_RELAXNG_VALUE:{
10201 xmlChar *content = NULL;
10202 xmlChar *oldvalue;
10203 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010204
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010205 child = node;
10206 while (child != NULL) {
10207 if (child->type == XML_ELEMENT_NODE) {
10208 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10209 node->parent->name);
10210 ret = -1;
10211 break;
10212 } else if ((child->type == XML_TEXT_NODE) ||
10213 (child->type == XML_CDATA_SECTION_NODE)) {
10214 content = xmlStrcat(content, child->content);
10215 }
10216 /* TODO: handle entities ... */
10217 child = child->next;
10218 }
10219 if (ret == -1) {
10220 if (content != NULL)
10221 xmlFree(content);
10222 break;
10223 }
10224 if (content == NULL) {
10225 content = xmlStrdup(BAD_CAST "");
10226 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010227 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010228 ret = -1;
10229 break;
10230 }
10231 }
10232 oldvalue = ctxt->state->value;
10233 ctxt->state->value = content;
10234 ret = xmlRelaxNGValidateValue(ctxt, define);
10235 ctxt->state->value = oldvalue;
10236 if (ret == -1) {
10237 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10238 } else if (ret == 0) {
10239 ctxt->state->seq = NULL;
10240 }
10241 if (content != NULL)
10242 xmlFree(content);
10243 break;
10244 }
10245 case XML_RELAXNG_LIST:{
10246 xmlChar *content;
10247 xmlNodePtr child;
10248 xmlChar *oldvalue, *oldendvalue;
10249 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010250
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010251 /*
10252 * Make sure it's only text nodes
10253 */
10254
10255 content = NULL;
10256 child = node;
10257 while (child != NULL) {
10258 if (child->type == XML_ELEMENT_NODE) {
10259 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10260 node->parent->name);
10261 ret = -1;
10262 break;
10263 } else if ((child->type == XML_TEXT_NODE) ||
10264 (child->type == XML_CDATA_SECTION_NODE)) {
10265 content = xmlStrcat(content, child->content);
10266 }
10267 /* TODO: handle entities ... */
10268 child = child->next;
10269 }
10270 if (ret == -1) {
10271 if (content != NULL)
10272 xmlFree(content);
10273 break;
10274 }
10275 if (content == NULL) {
10276 content = xmlStrdup(BAD_CAST "");
10277 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010278 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010279 ret = -1;
10280 break;
10281 }
10282 }
10283 len = xmlStrlen(content);
10284 oldvalue = ctxt->state->value;
10285 oldendvalue = ctxt->state->endvalue;
10286 ctxt->state->value = content;
10287 ctxt->state->endvalue = content + len;
10288 ret = xmlRelaxNGValidateValue(ctxt, define);
10289 ctxt->state->value = oldvalue;
10290 ctxt->state->endvalue = oldendvalue;
10291 if (ret == -1) {
10292 VALID_ERR(XML_RELAXNG_ERR_LIST);
10293 } else if ((ret == 0) && (node != NULL)) {
10294 ctxt->state->seq = node->next;
10295 }
10296 if (content != NULL)
10297 xmlFree(content);
10298 break;
10299 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010300 case XML_RELAXNG_EXCEPT:
10301 case XML_RELAXNG_PARAM:
10302 TODO ret = -1;
10303 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010304 }
10305 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010306#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010307 for (i = 0; i < ctxt->depth; i++)
10308 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010310 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010311 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010312 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010313 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010314 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010315 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010316 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010317#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010318 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010319}
10320
10321/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010322 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010323 * @ctxt: a Relax-NG validation context
10324 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010325 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010326 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010327 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010328 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010329 */
10330static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010331xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10332 xmlRelaxNGDefinePtr define)
10333{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010334 xmlRelaxNGStatesPtr states, res;
10335 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010336
Daniel Veillardfd573f12003-03-16 17:52:32 +000010337 /*
10338 * We should NOT have both ctxt->state and ctxt->states
10339 */
10340 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010341 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10342 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010343 }
10344
10345 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010346 if (ctxt->states != NULL) {
10347 ctxt->state = ctxt->states->tabState[0];
10348 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10349 ctxt->states = NULL;
10350 }
10351 ret = xmlRelaxNGValidateState(ctxt, define);
10352 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10353 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10354 ctxt->state = NULL;
10355 }
10356 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10357 ctxt->state = ctxt->states->tabState[0];
10358 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10359 ctxt->states = NULL;
10360 }
10361 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010362 }
10363
10364 states = ctxt->states;
10365 ctxt->states = NULL;
10366 res = NULL;
10367 j = 0;
10368 oldflags = ctxt->flags;
10369 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010370 for (i = 0; i < states->nbState; i++) {
10371 ctxt->state = states->tabState[i];
10372 ctxt->states = NULL;
10373 ret = xmlRelaxNGValidateState(ctxt, define);
10374 /*
10375 * We should NOT have both ctxt->state and ctxt->states
10376 */
10377 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10378 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10379 ctxt->state = NULL;
10380 }
10381 if (ret == 0) {
10382 if (ctxt->states == NULL) {
10383 if (res != NULL) {
10384 /* add the state to the container */
10385 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10386 ctxt->state = NULL;
10387 } else {
10388 /* add the state directly in states */
10389 states->tabState[j++] = ctxt->state;
10390 ctxt->state = NULL;
10391 }
10392 } else {
10393 if (res == NULL) {
10394 /* make it the new container and copy other results */
10395 res = ctxt->states;
10396 ctxt->states = NULL;
10397 for (k = 0; k < j; k++)
10398 xmlRelaxNGAddStates(ctxt, res,
10399 states->tabState[k]);
10400 } else {
10401 /* add all the new results to res and reff the container */
10402 for (k = 0; k < ctxt->states->nbState; k++)
10403 xmlRelaxNGAddStates(ctxt, res,
10404 ctxt->states->tabState[k]);
10405 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10406 ctxt->states = NULL;
10407 }
10408 }
10409 } else {
10410 if (ctxt->state != NULL) {
10411 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10412 ctxt->state = NULL;
10413 } else if (ctxt->states != NULL) {
10414 for (k = 0; k < ctxt->states->nbState; k++)
10415 xmlRelaxNGFreeValidState(ctxt,
10416 ctxt->states->tabState[k]);
10417 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10418 ctxt->states = NULL;
10419 }
10420 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010421 }
10422 ctxt->flags = oldflags;
10423 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010424 xmlRelaxNGFreeStates(ctxt, states);
10425 ctxt->states = res;
10426 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010427 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010428 states->nbState = j;
10429 ctxt->states = states;
10430 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010431 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010432 ctxt->state = states->tabState[0];
10433 xmlRelaxNGFreeStates(ctxt, states);
10434 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010435 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010436 ret = -1;
10437 xmlRelaxNGFreeStates(ctxt, states);
10438 if (ctxt->states != NULL) {
10439 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10440 ctxt->states = NULL;
10441 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010442 }
10443 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010444 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10445 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010446 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010447 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010448}
10449
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010450/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010451 * xmlRelaxNGValidateDocument:
10452 * @ctxt: a Relax-NG validation context
10453 * @doc: the document
10454 *
10455 * Validate the given document
10456 *
10457 * Returns 0 if the validation succeeded or an error code.
10458 */
10459static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010460xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10461{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010462 int ret;
10463 xmlRelaxNGPtr schema;
10464 xmlRelaxNGGrammarPtr grammar;
10465 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010466 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010467
10468 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010469 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010470
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010471 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010472 schema = ctxt->schema;
10473 grammar = schema->topgrammar;
10474 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010475 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10476 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010477 }
10478 state = xmlRelaxNGNewValidState(ctxt, NULL);
10479 ctxt->state = state;
10480 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010481 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010482 state = ctxt->state;
10483 node = state->seq;
10484 node = xmlRelaxNGSkipIgnored(ctxt, node);
10485 if (node != NULL) {
10486 if (ret != -1) {
10487 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10488 ret = -1;
10489 }
10490 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010491 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010492 int i;
10493 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010494
Daniel Veillard4c004142003-10-07 11:33:24 +000010495 for (i = 0; i < ctxt->states->nbState; i++) {
10496 state = ctxt->states->tabState[i];
10497 node = state->seq;
10498 node = xmlRelaxNGSkipIgnored(ctxt, node);
10499 if (node == NULL)
10500 tmp = 0;
10501 xmlRelaxNGFreeValidState(ctxt, state);
10502 }
10503 if (tmp == -1) {
10504 if (ret != -1) {
10505 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10506 ret = -1;
10507 }
10508 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010509 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010510 if (ctxt->state != NULL) {
10511 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010512 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010513 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010514 if (ret != 0)
10515 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010516#ifdef DEBUG
10517 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010518 ctxt->error(ctxt->userData,
10519 "%d Extra error messages left on stack !\n",
10520 ctxt->errNr);
10521 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010522 }
10523#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010524#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010525 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010526 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010527
Daniel Veillard4c004142003-10-07 11:33:24 +000010528 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10529 vctxt.valid = 1;
10530 vctxt.error = ctxt->error;
10531 vctxt.warning = ctxt->warning;
10532 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010533
Daniel Veillard4c004142003-10-07 11:33:24 +000010534 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10535 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010536 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010537#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010538 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010539 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010540
Daniel Veillard4c004142003-10-07 11:33:24 +000010541 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010542}
10543
Daniel Veillardfd573f12003-03-16 17:52:32 +000010544/************************************************************************
10545 * *
10546 * Validation interfaces *
10547 * *
10548 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010549
Daniel Veillard6eadf632003-01-23 18:29:16 +000010550/**
10551 * xmlRelaxNGNewValidCtxt:
10552 * @schema: a precompiled XML RelaxNGs
10553 *
10554 * Create an XML RelaxNGs validation context based on the given schema
10555 *
10556 * Returns the validation context or NULL in case of error
10557 */
10558xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010559xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10560{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010561 xmlRelaxNGValidCtxtPtr ret;
10562
10563 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10564 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010565 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010566 return (NULL);
10567 }
10568 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10569 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010570 ret->error = xmlGenericError;
10571 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010572 ret->errNr = 0;
10573 ret->errMax = 0;
10574 ret->err = NULL;
10575 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010576 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010577 ret->states = NULL;
10578 ret->freeState = NULL;
10579 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010580 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010581 return (ret);
10582}
10583
10584/**
10585 * xmlRelaxNGFreeValidCtxt:
10586 * @ctxt: the schema validation context
10587 *
10588 * Free the resources associated to the schema validation context
10589 */
10590void
Daniel Veillard4c004142003-10-07 11:33:24 +000010591xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10592{
Daniel Veillard798024a2003-03-19 10:36:09 +000010593 int k;
10594
Daniel Veillard6eadf632003-01-23 18:29:16 +000010595 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010596 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010597 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010598 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010599 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010600 for (k = 0; k < ctxt->freeState->nbState; k++) {
10601 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10602 }
10603 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010604 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010605 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010606 for (k = 0; k < ctxt->freeStatesNr; k++) {
10607 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10608 }
10609 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010610 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010611 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010612 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010613 if (ctxt->elemTab != NULL) {
10614 xmlRegExecCtxtPtr exec;
10615
Daniel Veillard4c004142003-10-07 11:33:24 +000010616 exec = xmlRelaxNGElemPop(ctxt);
10617 while (exec != NULL) {
10618 xmlRegFreeExecCtxt(exec);
10619 exec = xmlRelaxNGElemPop(ctxt);
10620 }
10621 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010622 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010623 xmlFree(ctxt);
10624}
10625
10626/**
10627 * xmlRelaxNGSetValidErrors:
10628 * @ctxt: a Relax-NG validation context
10629 * @err: the error function
10630 * @warn: the warning function
10631 * @ctx: the functions context
10632 *
10633 * Set the error and warning callback informations
10634 */
10635void
10636xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010637 xmlRelaxNGValidityErrorFunc err,
10638 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10639{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010640 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010641 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010642 ctxt->error = err;
10643 ctxt->warning = warn;
10644 ctxt->userData = ctx;
10645}
10646
10647/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010648 * xmlRelaxNGGetValidErrors:
10649 * @ctxt: a Relax-NG validation context
10650 * @err: the error function result
10651 * @warn: the warning function result
10652 * @ctx: the functions context result
10653 *
10654 * Get the error and warning callback informations
10655 *
10656 * Returns -1 in case of error and 0 otherwise
10657 */
10658int
10659xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010660 xmlRelaxNGValidityErrorFunc * err,
10661 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10662{
Daniel Veillard409a8142003-07-18 15:16:57 +000010663 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010664 return (-1);
10665 if (err != NULL)
10666 *err = ctxt->error;
10667 if (warn != NULL)
10668 *warn = ctxt->warning;
10669 if (ctx != NULL)
10670 *ctx = ctxt->userData;
10671 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010672}
10673
10674/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010675 * xmlRelaxNGValidateDoc:
10676 * @ctxt: a Relax-NG validation context
10677 * @doc: a parsed document tree
10678 *
10679 * Validate a document tree in memory.
10680 *
10681 * Returns 0 if the document is valid, a positive error code
10682 * number otherwise and -1 in case of internal or API error.
10683 */
10684int
Daniel Veillard4c004142003-10-07 11:33:24 +000010685xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10686{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010687 int ret;
10688
10689 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010690 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010691
10692 ctxt->doc = doc;
10693
10694 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010695 /*
10696 * TODO: build error codes
10697 */
10698 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010699 return (1);
10700 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010701}
10702
10703#endif /* LIBXML_SCHEMAS_ENABLED */