blob: c6ce9361053fc9077faf0dec3b9b0ba29959a6f5 [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)
Daniel Veillard24505b02005-07-28 23:49:35 +00001480 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001481 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];
Daniel Veillard24505b02005-07-28 23:49:35 +00001487 ctxt->incTab[ctxt->incNr] = NULL;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001488 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)
Daniel Veillard24505b02005-07-28 23:49:35 +00001892 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001893 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];
Daniel Veillard24505b02005-07-28 23:49:35 +00001899 ctxt->docTab[ctxt->docNr] = NULL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001900 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
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002223#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002224 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002225#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002226 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2227 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002228 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002229
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002230 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002231 ctxt->errNo = err;
2232 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2233 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002234 xmlFree(msg);
2235}
2236
2237/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002238 * xmlRelaxNGPopErrors:
2239 * @ctxt: the validation context
2240 * @level: the error level in the stack
2241 *
2242 * pop and discard all errors until the given level is reached
2243 */
2244static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002245xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2246{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002247 int i;
2248 xmlRelaxNGValidErrorPtr err;
2249
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002250#ifdef DEBUG_ERROR
2251 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002252 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002253#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002254 for (i = level; i < ctxt->errNr; i++) {
2255 err = &ctxt->errTab[i];
2256 if (err->flags & ERROR_IS_DUP) {
2257 if (err->arg1 != NULL)
2258 xmlFree((xmlChar *) err->arg1);
2259 err->arg1 = NULL;
2260 if (err->arg2 != NULL)
2261 xmlFree((xmlChar *) err->arg2);
2262 err->arg2 = NULL;
2263 err->flags = 0;
2264 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002265 }
2266 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002267 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002268 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002269}
Daniel Veillard4c004142003-10-07 11:33:24 +00002270
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002271/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002272 * xmlRelaxNGDumpValidError:
2273 * @ctxt: the validation context
2274 *
2275 * Show all validation error over a given index.
2276 */
2277static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002278xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2279{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002280 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002281 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002282
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002283#ifdef DEBUG_ERROR
2284 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002285 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002286#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002287 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2288 err = &ctxt->errTab[i];
2289 if (k < MAX_ERROR) {
2290 for (j = 0; j < i; j++) {
2291 dup = &ctxt->errTab[j];
2292 if ((err->err == dup->err) && (err->node == dup->node) &&
2293 (xmlStrEqual(err->arg1, dup->arg1)) &&
2294 (xmlStrEqual(err->arg2, dup->arg2))) {
2295 goto skip;
2296 }
2297 }
2298 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2299 err->arg1, err->arg2);
2300 k++;
2301 }
2302 skip:
2303 if (err->flags & ERROR_IS_DUP) {
2304 if (err->arg1 != NULL)
2305 xmlFree((xmlChar *) err->arg1);
2306 err->arg1 = NULL;
2307 if (err->arg2 != NULL)
2308 xmlFree((xmlChar *) err->arg2);
2309 err->arg2 = NULL;
2310 err->flags = 0;
2311 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002312 }
2313 ctxt->errNr = 0;
2314}
Daniel Veillard4c004142003-10-07 11:33:24 +00002315
Daniel Veillard42f12e92003-03-07 18:32:59 +00002316/**
2317 * xmlRelaxNGAddValidError:
2318 * @ctxt: the validation context
2319 * @err: the error number
2320 * @arg1: the first argument
2321 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002322 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002323 *
2324 * Register a validation error, either generating it if it's sure
2325 * or stacking it for later handling if unsure.
2326 */
2327static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002328xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2329 xmlRelaxNGValidErr err, const xmlChar * arg1,
2330 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002331{
Daniel Veillarde40afec2005-09-03 14:28:02 +00002332 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002333 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002334
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002335#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002336 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002337#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002338 /*
2339 * generate the error directly
2340 */
William M. Brack60929622004-03-27 17:54:18 +00002341 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2342 (ctxt->flags & FLAGS_NEGATIVE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002343 xmlNodePtr node, seq;
2344
2345 /*
2346 * Flush first any stacked error which might be the
2347 * real cause of the problem.
2348 */
2349 if (ctxt->errNr != 0)
2350 xmlRelaxNGDumpValidError(ctxt);
2351 if (ctxt->state != NULL) {
2352 node = ctxt->state->node;
2353 seq = ctxt->state->seq;
2354 } else {
2355 node = seq = NULL;
2356 }
2357 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002358 }
2359 /*
2360 * Stack the error for later processing if needed
2361 */
2362 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002363 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002364 }
2365}
2366
Daniel Veillard6eadf632003-01-23 18:29:16 +00002367
2368/************************************************************************
2369 * *
2370 * Type library hooks *
2371 * *
2372 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002373static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002374 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002375
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002376/**
2377 * xmlRelaxNGSchemaTypeHave:
2378 * @data: data needed for the library
2379 * @type: the type name
2380 *
2381 * Check if the given type is provided by
2382 * the W3C XMLSchema Datatype library.
2383 *
2384 * Returns 1 if yes, 0 if no and -1 in case of error.
2385 */
2386static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002387xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2388{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002389 xmlSchemaTypePtr typ;
2390
2391 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002392 return (-1);
2393 typ = xmlSchemaGetPredefinedType(type,
2394 BAD_CAST
2395 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002396 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002397 return (0);
2398 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002399}
2400
2401/**
2402 * xmlRelaxNGSchemaTypeCheck:
2403 * @data: data needed for the library
2404 * @type: the type name
2405 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002406 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002407 *
2408 * Check if the given type and value are validated by
2409 * the W3C XMLSchema Datatype library.
2410 *
2411 * Returns 1 if yes, 0 if no and -1 in case of error.
2412 */
2413static int
2414xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002415 const xmlChar * type,
2416 const xmlChar * value,
2417 void **result, xmlNodePtr node)
2418{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002419 xmlSchemaTypePtr typ;
2420 int ret;
2421
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002422 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002423 return (-1);
2424 typ = xmlSchemaGetPredefinedType(type,
2425 BAD_CAST
2426 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002427 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002428 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002429 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002430 (xmlSchemaValPtr *) result, node);
2431 if (ret == 2) /* special ID error code */
2432 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002433 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002434 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002435 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002436 return (0);
2437 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002438}
2439
2440/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002441 * xmlRelaxNGSchemaFacetCheck:
2442 * @data: data needed for the library
2443 * @type: the type name
2444 * @facet: the facet name
2445 * @val: the facet value
2446 * @strval: the string value
2447 * @value: the value to check
2448 *
2449 * Function provided by a type library to check a value facet
2450 *
2451 * Returns 1 if yes, 0 if no and -1 in case of error.
2452 */
2453static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002454xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2455 const xmlChar * type, const xmlChar * facetname,
2456 const xmlChar * val, const xmlChar * strval,
2457 void *value)
2458{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002459 xmlSchemaFacetPtr facet;
2460 xmlSchemaTypePtr typ;
2461 int ret;
2462
2463 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002464 return (-1);
2465 typ = xmlSchemaGetPredefinedType(type,
2466 BAD_CAST
2467 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002468 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002469 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002470
2471 facet = xmlSchemaNewFacet();
2472 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002473 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002474
Daniel Veillard4c004142003-10-07 11:33:24 +00002475 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002476 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002477 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002478 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002479 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002480 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002481 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002482 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002483 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002484 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002485 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002486 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002487 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002488 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002489 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002490 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002491 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002492 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002493 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002494 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002495 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002496 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2497 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2498 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2499 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002500 xmlSchemaFreeFacet(facet);
2501 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002502 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002503 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002504 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2505 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002506 xmlSchemaFreeFacet(facet);
2507 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002508 }
2509 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2510 xmlSchemaFreeFacet(facet);
2511 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002512 return (-1);
2513 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002514}
2515
2516/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002517 * xmlRelaxNGSchemaFreeValue:
2518 * @data: data needed for the library
2519 * @value: the value to free
2520 *
2521 * Function provided by a type library to free a Schemas value
2522 *
2523 * Returns 1 if yes, 0 if no and -1 in case of error.
2524 */
2525static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002526xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2527{
Daniel Veillard80b19092003-03-28 13:29:53 +00002528 xmlSchemaFreeValue(value);
2529}
2530
2531/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002532 * xmlRelaxNGSchemaTypeCompare:
2533 * @data: data needed for the library
2534 * @type: the type name
2535 * @value1: the first value
2536 * @value2: the second value
2537 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002538 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002539 * Datatype library.
2540 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002541 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002542 */
2543static int
2544xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002545 const xmlChar * type,
2546 const xmlChar * value1,
2547 xmlNodePtr ctxt1,
2548 void *comp1,
2549 const xmlChar * value2, xmlNodePtr ctxt2)
2550{
Daniel Veillard80b19092003-03-28 13:29:53 +00002551 int ret;
2552 xmlSchemaTypePtr typ;
2553 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2554
2555 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002556 return (-1);
2557 typ = xmlSchemaGetPredefinedType(type,
2558 BAD_CAST
2559 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002560 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002561 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002562 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002563 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2564 if (ret != 0)
2565 return (-1);
2566 if (res1 == NULL)
2567 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002568 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002569 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002570 }
2571 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002572 if (ret != 0) {
Daniel Veillardf4644032005-06-13 11:41:31 +00002573 if ((comp1 == NULL) && (res1 != NULL))
2574 xmlSchemaFreeValue(res1);
Daniel Veillard4c004142003-10-07 11:33:24 +00002575 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002576 }
2577 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002578 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002579 }
2580 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002581 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002582 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002583 xmlSchemaFreeValue(res2);
2584 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002585 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002586 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002587 return (1);
2588 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002589}
Daniel Veillard4c004142003-10-07 11:33:24 +00002590
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002591/**
2592 * xmlRelaxNGDefaultTypeHave:
2593 * @data: data needed for the library
2594 * @type: the type name
2595 *
2596 * Check if the given type is provided by
2597 * the default datatype library.
2598 *
2599 * Returns 1 if yes, 0 if no and -1 in case of error.
2600 */
2601static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002602xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2603 const xmlChar * type)
2604{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002605 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002606 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002607 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002608 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002609 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002610 return (1);
2611 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002612}
2613
2614/**
2615 * xmlRelaxNGDefaultTypeCheck:
2616 * @data: data needed for the library
2617 * @type: the type name
2618 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002619 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002620 *
2621 * Check if the given type and value are validated by
2622 * the default datatype library.
2623 *
2624 * Returns 1 if yes, 0 if no and -1 in case of error.
2625 */
2626static int
2627xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002628 const xmlChar * type ATTRIBUTE_UNUSED,
2629 const xmlChar * value ATTRIBUTE_UNUSED,
2630 void **result ATTRIBUTE_UNUSED,
2631 xmlNodePtr node ATTRIBUTE_UNUSED)
2632{
Daniel Veillardd4310742003-02-18 21:12:46 +00002633 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002634 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002635 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002636 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002637 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002638 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002639 }
2640
Daniel Veillard4c004142003-10-07 11:33:24 +00002641 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002642}
2643
2644/**
2645 * xmlRelaxNGDefaultTypeCompare:
2646 * @data: data needed for the library
2647 * @type: the type name
2648 * @value1: the first value
2649 * @value2: the second value
2650 *
2651 * Compare two values accordingly a type from the default
2652 * datatype library.
2653 *
2654 * Returns 1 if yes, 0 if no and -1 in case of error.
2655 */
2656static int
2657xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002658 const xmlChar * type,
2659 const xmlChar * value1,
2660 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2661 void *comp1 ATTRIBUTE_UNUSED,
2662 const xmlChar * value2,
2663 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2664{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002665 int ret = -1;
2666
2667 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002668 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002669 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002670 if (!xmlStrEqual(value1, value2)) {
2671 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002672
Daniel Veillard4c004142003-10-07 11:33:24 +00002673 /*
2674 * TODO: trivial optimizations are possible by
2675 * computing at compile-time
2676 */
2677 nval = xmlRelaxNGNormalize(NULL, value1);
2678 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002679
Daniel Veillard4c004142003-10-07 11:33:24 +00002680 if ((nval == NULL) || (nvalue == NULL))
2681 ret = -1;
2682 else if (xmlStrEqual(nval, nvalue))
2683 ret = 1;
2684 else
2685 ret = 0;
2686 if (nval != NULL)
2687 xmlFree(nval);
2688 if (nvalue != NULL)
2689 xmlFree(nvalue);
2690 } else
2691 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002692 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002693 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002694}
Daniel Veillard4c004142003-10-07 11:33:24 +00002695
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002696static int xmlRelaxNGTypeInitialized = 0;
2697static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2698
2699/**
2700 * xmlRelaxNGFreeTypeLibrary:
2701 * @lib: the type library structure
2702 * @namespace: the URI bound to the library
2703 *
2704 * Free the structure associated to the type library
2705 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002706static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002707xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002708 const xmlChar * namespace ATTRIBUTE_UNUSED)
2709{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002710 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002711 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002712 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002713 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002714 xmlFree(lib);
2715}
2716
2717/**
2718 * xmlRelaxNGRegisterTypeLibrary:
2719 * @namespace: the URI bound to the library
2720 * @data: data associated to the library
2721 * @have: the provide function
2722 * @check: the checking function
2723 * @comp: the comparison function
2724 *
2725 * Register a new type library
2726 *
2727 * Returns 0 in case of success and -1 in case of error.
2728 */
2729static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002730xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2731 xmlRelaxNGTypeHave have,
2732 xmlRelaxNGTypeCheck check,
2733 xmlRelaxNGTypeCompare comp,
2734 xmlRelaxNGFacetCheck facet,
2735 xmlRelaxNGTypeFree freef)
2736{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002737 xmlRelaxNGTypeLibraryPtr lib;
2738 int ret;
2739
2740 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002741 (check == NULL) || (comp == NULL))
2742 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002743 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002744 xmlGenericError(xmlGenericErrorContext,
2745 "Relax-NG types library '%s' already registered\n",
2746 namespace);
2747 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002748 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002749 lib =
2750 (xmlRelaxNGTypeLibraryPtr)
2751 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002752 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002753 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002754 return (-1);
2755 }
2756 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2757 lib->namespace = xmlStrdup(namespace);
2758 lib->data = data;
2759 lib->have = have;
2760 lib->comp = comp;
2761 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002762 lib->facet = facet;
2763 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002764 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2765 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002766 xmlGenericError(xmlGenericErrorContext,
2767 "Relax-NG types library failed to register '%s'\n",
2768 namespace);
2769 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2770 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002771 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002772 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002773}
2774
2775/**
2776 * xmlRelaxNGInitTypes:
2777 *
2778 * Initilize the default type libraries.
2779 *
2780 * Returns 0 in case of success and -1 in case of error.
2781 */
Daniel Veillarddd6d3002004-11-03 14:20:29 +00002782int
Daniel Veillard4c004142003-10-07 11:33:24 +00002783xmlRelaxNGInitTypes(void)
2784{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002785 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002786 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002787 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2788 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002789 xmlGenericError(xmlGenericErrorContext,
2790 "Failed to allocate sh table for Relax-NG types\n");
2791 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002792 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002793 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2794 "http://www.w3.org/2001/XMLSchema-datatypes",
2795 NULL, xmlRelaxNGSchemaTypeHave,
2796 xmlRelaxNGSchemaTypeCheck,
2797 xmlRelaxNGSchemaTypeCompare,
2798 xmlRelaxNGSchemaFacetCheck,
2799 xmlRelaxNGSchemaFreeValue);
2800 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2801 xmlRelaxNGDefaultTypeHave,
2802 xmlRelaxNGDefaultTypeCheck,
2803 xmlRelaxNGDefaultTypeCompare, NULL,
2804 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002805 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002806 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002807}
2808
2809/**
2810 * xmlRelaxNGCleanupTypes:
2811 *
2812 * Cleanup the default Schemas type library associated to RelaxNG
2813 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002814void
2815xmlRelaxNGCleanupTypes(void)
2816{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002817 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002818 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002819 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002820 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002821 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002822 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002823}
2824
2825/************************************************************************
2826 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002827 * Compiling element content into regexp *
2828 * *
2829 * Sometime the element content can be compiled into a pure regexp, *
2830 * This allows a faster execution and streamability at that level *
2831 * *
2832 ************************************************************************/
2833
Daniel Veillard52b48c72003-04-13 19:53:42 +00002834static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2835 xmlRelaxNGDefinePtr def);
2836
Daniel Veillard952379b2003-03-17 15:37:12 +00002837/**
2838 * xmlRelaxNGIsCompileable:
2839 * @define: the definition to check
2840 *
2841 * Check if a definition is nullable.
2842 *
2843 * Returns 1 if yes, 0 if no and -1 in case of error
2844 */
2845static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002846xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2847{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002848 int ret = -1;
2849
Daniel Veillard952379b2003-03-17 15:37:12 +00002850 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002851 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002852 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002853 if ((def->type != XML_RELAXNG_ELEMENT) &&
2854 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002855 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002856 if ((def->type != XML_RELAXNG_ELEMENT) &&
2857 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002858 return (0);
2859 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002860 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002861 ret = xmlRelaxNGIsCompileable(def->content);
2862 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002863 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002864 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002865 ret = 1;
2866 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002867 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002868 /*
2869 * Check if the element content is compileable
2870 */
2871 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2872 ((def->dflags & IS_COMPILABLE) == 0)) {
2873 xmlRelaxNGDefinePtr list;
2874
2875 list = def->content;
2876 while (list != NULL) {
2877 ret = xmlRelaxNGIsCompileable(list);
2878 if (ret != 1)
2879 break;
2880 list = list->next;
2881 }
William M. Brack60929622004-03-27 17:54:18 +00002882 /*
2883 * Because the routine is recursive, we must guard against
2884 * discovering both COMPILABLE and NOT_COMPILABLE
2885 */
2886 if (ret == 0) {
2887 def->dflags &= ~IS_COMPILABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002888 def->dflags |= IS_NOT_COMPILABLE;
William M. Brack60929622004-03-27 17:54:18 +00002889 }
2890 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002891 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002892#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002893 if (ret == 1) {
2894 xmlGenericError(xmlGenericErrorContext,
2895 "element content for %s is compilable\n",
2896 def->name);
2897 } else if (ret == 0) {
2898 xmlGenericError(xmlGenericErrorContext,
2899 "element content for %s is not compilable\n",
2900 def->name);
2901 } else {
2902 xmlGenericError(xmlGenericErrorContext,
2903 "Problem in RelaxNGIsCompileable for element %s\n",
2904 def->name);
2905 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002906#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002907 }
2908 /*
2909 * All elements return a compileable status unless they
2910 * are generic like anyName
2911 */
2912 if ((def->nameClass != NULL) || (def->name == NULL))
2913 ret = 0;
2914 else
2915 ret = 1;
2916 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002917 case XML_RELAXNG_REF:
2918 case XML_RELAXNG_EXTERNALREF:
2919 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002920 if (def->depth == -20) {
2921 return (1);
2922 } else {
2923 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002924
Daniel Veillard4c004142003-10-07 11:33:24 +00002925 def->depth = -20;
2926 list = def->content;
2927 while (list != NULL) {
2928 ret = xmlRelaxNGIsCompileable(list);
2929 if (ret != 1)
2930 break;
2931 list = list->next;
2932 }
2933 }
2934 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002935 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002936 case XML_RELAXNG_OPTIONAL:
2937 case XML_RELAXNG_ZEROORMORE:
2938 case XML_RELAXNG_ONEORMORE:
2939 case XML_RELAXNG_CHOICE:
2940 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002941 case XML_RELAXNG_DEF:{
2942 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002943
Daniel Veillard4c004142003-10-07 11:33:24 +00002944 list = def->content;
2945 while (list != NULL) {
2946 ret = xmlRelaxNGIsCompileable(list);
2947 if (ret != 1)
2948 break;
2949 list = list->next;
2950 }
2951 break;
2952 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002953 case XML_RELAXNG_EXCEPT:
2954 case XML_RELAXNG_ATTRIBUTE:
2955 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002956 case XML_RELAXNG_DATATYPE:
2957 case XML_RELAXNG_LIST:
2958 case XML_RELAXNG_PARAM:
2959 case XML_RELAXNG_VALUE:
Daniel Veillard952379b2003-03-17 15:37:12 +00002960 case XML_RELAXNG_NOT_ALLOWED:
William M. Brack7e29c0a2004-04-02 09:07:22 +00002961 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002962 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002963 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002964 if (ret == 0)
2965 def->dflags |= IS_NOT_COMPILABLE;
2966 if (ret == 1)
2967 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002968#ifdef DEBUG_COMPILE
2969 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002970 xmlGenericError(xmlGenericErrorContext,
2971 "RelaxNGIsCompileable %s : true\n",
2972 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002973 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002974 xmlGenericError(xmlGenericErrorContext,
2975 "RelaxNGIsCompileable %s : false\n",
2976 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002977 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002978 xmlGenericError(xmlGenericErrorContext,
2979 "Problem in RelaxNGIsCompileable %s\n",
2980 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002981 }
2982#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002983 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002984}
2985
2986/**
2987 * xmlRelaxNGCompile:
2988 * ctxt: the RelaxNG parser context
2989 * @define: the definition tree to compile
2990 *
2991 * Compile the set of definitions, it works recursively, till the
2992 * element boundaries, where it tries to compile the content if possible
2993 *
2994 * Returns 0 if success and -1 in case of error
2995 */
2996static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002997xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
2998{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002999 int ret = 0;
3000 xmlRelaxNGDefinePtr list;
3001
Daniel Veillard4c004142003-10-07 11:33:24 +00003002 if ((ctxt == NULL) || (def == NULL))
3003 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003004
Daniel Veillard4c004142003-10-07 11:33:24 +00003005 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003006 case XML_RELAXNG_START:
3007 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003008 xmlAutomataPtr oldam = ctxt->am;
3009 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003010
3011 def->depth = -25;
3012
Daniel Veillard4c004142003-10-07 11:33:24 +00003013 list = def->content;
3014 ctxt->am = xmlNewAutomata();
3015 if (ctxt->am == NULL)
3016 return (-1);
3017 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3018 while (list != NULL) {
3019 xmlRelaxNGCompile(ctxt, list);
3020 list = list->next;
3021 }
3022 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3023 def->contModel = xmlAutomataCompile(ctxt->am);
3024 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003025
Daniel Veillard4c004142003-10-07 11:33:24 +00003026 xmlFreeAutomata(ctxt->am);
3027 ctxt->state = oldstate;
3028 ctxt->am = oldam;
3029 }
3030 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003031 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003032 if ((ctxt->am != NULL) && (def->name != NULL)) {
3033 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3034 ctxt->state, NULL,
3035 def->name, def->ns,
3036 def);
3037 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003038 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003039 xmlAutomataPtr oldam = ctxt->am;
3040 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003041
3042 def->depth = -25;
3043
Daniel Veillard4c004142003-10-07 11:33:24 +00003044 list = def->content;
3045 ctxt->am = xmlNewAutomata();
3046 if (ctxt->am == NULL)
3047 return (-1);
3048 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3049 while (list != NULL) {
3050 xmlRelaxNGCompile(ctxt, list);
3051 list = list->next;
3052 }
3053 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3054 def->contModel = xmlAutomataCompile(ctxt->am);
3055 if (!xmlRegexpIsDeterminist(def->contModel)) {
3056 /*
3057 * we can only use the automata if it is determinist
3058 */
3059 xmlRegFreeRegexp(def->contModel);
3060 def->contModel = NULL;
3061 }
3062 xmlFreeAutomata(ctxt->am);
3063 ctxt->state = oldstate;
3064 ctxt->am = oldam;
3065 } else {
3066 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003067
Daniel Veillard4c004142003-10-07 11:33:24 +00003068 /*
3069 * we can't build the content model for this element content
3070 * but it still might be possible to build it for some of its
3071 * children, recurse.
3072 */
3073 ret = xmlRelaxNGTryCompile(ctxt, def);
3074 ctxt->am = oldam;
3075 }
3076 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003077 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003078 ret = xmlRelaxNGCompile(ctxt, def->content);
3079 break;
3080 case XML_RELAXNG_OPTIONAL:{
3081 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003082
Daniel Veillard4c004142003-10-07 11:33:24 +00003083 xmlRelaxNGCompile(ctxt, def->content);
3084 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3085 break;
3086 }
3087 case XML_RELAXNG_ZEROORMORE:{
3088 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003089
Daniel Veillard4c004142003-10-07 11:33:24 +00003090 ctxt->state =
3091 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3092 oldstate = ctxt->state;
3093 list = def->content;
3094 while (list != NULL) {
3095 xmlRelaxNGCompile(ctxt, list);
3096 list = list->next;
3097 }
3098 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3099 ctxt->state =
3100 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3101 break;
3102 }
3103 case XML_RELAXNG_ONEORMORE:{
3104 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003105
Daniel Veillard4c004142003-10-07 11:33:24 +00003106 list = def->content;
3107 while (list != NULL) {
3108 xmlRelaxNGCompile(ctxt, list);
3109 list = list->next;
3110 }
3111 oldstate = ctxt->state;
3112 list = def->content;
3113 while (list != NULL) {
3114 xmlRelaxNGCompile(ctxt, list);
3115 list = list->next;
3116 }
3117 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3118 ctxt->state =
3119 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3120 break;
3121 }
3122 case XML_RELAXNG_CHOICE:{
3123 xmlAutomataStatePtr target = NULL;
3124 xmlAutomataStatePtr oldstate = ctxt->state;
3125
3126 list = def->content;
3127 while (list != NULL) {
3128 ctxt->state = oldstate;
3129 ret = xmlRelaxNGCompile(ctxt, list);
3130 if (ret != 0)
3131 break;
3132 if (target == NULL)
3133 target = ctxt->state;
3134 else {
3135 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3136 target);
3137 }
3138 list = list->next;
3139 }
3140 ctxt->state = target;
3141
3142 break;
3143 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003144 case XML_RELAXNG_REF:
3145 case XML_RELAXNG_EXTERNALREF:
3146 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003147 case XML_RELAXNG_GROUP:
3148 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003149 list = def->content;
3150 while (list != NULL) {
3151 ret = xmlRelaxNGCompile(ctxt, list);
3152 if (ret != 0)
3153 break;
3154 list = list->next;
3155 }
3156 break;
3157 case XML_RELAXNG_TEXT:{
3158 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003159
Daniel Veillard4c004142003-10-07 11:33:24 +00003160 ctxt->state =
3161 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3162 oldstate = ctxt->state;
3163 xmlRelaxNGCompile(ctxt, def->content);
3164 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3165 ctxt->state, BAD_CAST "#text",
3166 NULL);
3167 ctxt->state =
3168 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3169 break;
3170 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003171 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003172 ctxt->state =
3173 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3174 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003175 case XML_RELAXNG_EXCEPT:
3176 case XML_RELAXNG_ATTRIBUTE:
3177 case XML_RELAXNG_INTERLEAVE:
3178 case XML_RELAXNG_NOT_ALLOWED:
3179 case XML_RELAXNG_DATATYPE:
3180 case XML_RELAXNG_LIST:
3181 case XML_RELAXNG_PARAM:
3182 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003183 /* This should not happen and generate an internal error */
3184 fprintf(stderr, "RNG internal error trying to compile %s\n",
3185 xmlRelaxNGDefName(def));
3186 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003187 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003188 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003189}
3190
3191/**
3192 * xmlRelaxNGTryCompile:
3193 * ctxt: the RelaxNG parser context
3194 * @define: the definition tree to compile
3195 *
3196 * Try to compile the set of definitions, it works recursively,
3197 * possibly ignoring parts which cannot be compiled.
3198 *
3199 * Returns 0 if success and -1 in case of error
3200 */
3201static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003202xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3203{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003204 int ret = 0;
3205 xmlRelaxNGDefinePtr list;
3206
Daniel Veillard4c004142003-10-07 11:33:24 +00003207 if ((ctxt == NULL) || (def == NULL))
3208 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003209
3210 if ((def->type == XML_RELAXNG_START) ||
3211 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003212 ret = xmlRelaxNGIsCompileable(def);
3213 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3214 ctxt->am = NULL;
3215 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003216#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003217 if (ret == 0) {
3218 if (def->type == XML_RELAXNG_START)
3219 xmlGenericError(xmlGenericErrorContext,
3220 "compiled the start\n");
3221 else
3222 xmlGenericError(xmlGenericErrorContext,
3223 "compiled element %s\n", def->name);
3224 } else {
3225 if (def->type == XML_RELAXNG_START)
3226 xmlGenericError(xmlGenericErrorContext,
3227 "failed to compile the start\n");
3228 else
3229 xmlGenericError(xmlGenericErrorContext,
3230 "failed to compile element %s\n",
3231 def->name);
3232 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003233#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003234 return (ret);
3235 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003236 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003237 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003238 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003239 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3240 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003241 case XML_RELAXNG_TEXT:
3242 case XML_RELAXNG_DATATYPE:
3243 case XML_RELAXNG_LIST:
3244 case XML_RELAXNG_PARAM:
3245 case XML_RELAXNG_VALUE:
3246 case XML_RELAXNG_EMPTY:
3247 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003248 ret = 0;
3249 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003250 case XML_RELAXNG_OPTIONAL:
3251 case XML_RELAXNG_ZEROORMORE:
3252 case XML_RELAXNG_ONEORMORE:
3253 case XML_RELAXNG_CHOICE:
3254 case XML_RELAXNG_GROUP:
3255 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003256 case XML_RELAXNG_START:
3257 case XML_RELAXNG_REF:
3258 case XML_RELAXNG_EXTERNALREF:
3259 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003260 list = def->content;
3261 while (list != NULL) {
3262 ret = xmlRelaxNGTryCompile(ctxt, list);
3263 if (ret != 0)
3264 break;
3265 list = list->next;
3266 }
3267 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003268 case XML_RELAXNG_EXCEPT:
3269 case XML_RELAXNG_ATTRIBUTE:
3270 case XML_RELAXNG_INTERLEAVE:
3271 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003272 ret = 0;
3273 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003274 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003275 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003276}
3277
3278/************************************************************************
3279 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003280 * Parsing functions *
3281 * *
3282 ************************************************************************/
3283
Daniel Veillard4c004142003-10-07 11:33:24 +00003284static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3285 ctxt, xmlNodePtr node);
3286static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3287 ctxt, xmlNodePtr node);
3288static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3289 ctxt, xmlNodePtr nodes,
3290 int group);
3291static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3292 ctxt, xmlNodePtr node);
3293static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3294 xmlNodePtr node);
3295static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3296 xmlNodePtr nodes);
3297static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3298 ctxt, xmlNodePtr node,
3299 xmlRelaxNGDefinePtr
3300 def);
3301static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3302 ctxt, xmlNodePtr nodes);
3303static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3304 xmlRelaxNGDefinePtr define,
3305 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003306
3307
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003308#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003309
3310/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003311 * xmlRelaxNGIsNullable:
3312 * @define: the definition to verify
3313 *
3314 * Check if a definition is nullable.
3315 *
3316 * Returns 1 if yes, 0 if no and -1 in case of error
3317 */
3318static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003319xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3320{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003321 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003322
Daniel Veillardfd573f12003-03-16 17:52:32 +00003323 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003324 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003325
Daniel Veillarde063f482003-03-21 16:53:17 +00003326 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003327 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003328 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003329 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003330 switch (define->type) {
3331 case XML_RELAXNG_EMPTY:
3332 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003333 ret = 1;
3334 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003335 case XML_RELAXNG_NOOP:
3336 case XML_RELAXNG_DEF:
3337 case XML_RELAXNG_REF:
3338 case XML_RELAXNG_EXTERNALREF:
3339 case XML_RELAXNG_PARENTREF:
3340 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003341 ret = xmlRelaxNGIsNullable(define->content);
3342 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003343 case XML_RELAXNG_EXCEPT:
3344 case XML_RELAXNG_NOT_ALLOWED:
3345 case XML_RELAXNG_ELEMENT:
3346 case XML_RELAXNG_DATATYPE:
3347 case XML_RELAXNG_PARAM:
3348 case XML_RELAXNG_VALUE:
3349 case XML_RELAXNG_LIST:
3350 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003351 ret = 0;
3352 break;
3353 case XML_RELAXNG_CHOICE:{
3354 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003355
Daniel Veillard4c004142003-10-07 11:33:24 +00003356 while (list != NULL) {
3357 ret = xmlRelaxNGIsNullable(list);
3358 if (ret != 0)
3359 goto done;
3360 list = list->next;
3361 }
3362 ret = 0;
3363 break;
3364 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003365 case XML_RELAXNG_START:
3366 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003367 case XML_RELAXNG_GROUP:{
3368 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003369
Daniel Veillard4c004142003-10-07 11:33:24 +00003370 while (list != NULL) {
3371 ret = xmlRelaxNGIsNullable(list);
3372 if (ret != 1)
3373 goto done;
3374 list = list->next;
3375 }
3376 return (1);
3377 }
3378 default:
3379 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003380 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003381 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003382 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003383 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003384 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003385 define->dflags |= IS_NULLABLE;
3386 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003387}
3388
3389/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003390 * xmlRelaxNGIsBlank:
3391 * @str: a string
3392 *
3393 * Check if a string is ignorable c.f. 4.2. Whitespace
3394 *
3395 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3396 */
3397static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003398xmlRelaxNGIsBlank(xmlChar * str)
3399{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003400 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003401 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003402 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003403 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003404 return (0);
3405 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003406 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003407 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003408}
3409
Daniel Veillard6eadf632003-01-23 18:29:16 +00003410/**
3411 * xmlRelaxNGGetDataTypeLibrary:
3412 * @ctxt: a Relax-NG parser context
3413 * @node: the current data or value element
3414 *
3415 * Applies algorithm from 4.3. datatypeLibrary attribute
3416 *
3417 * Returns the datatypeLibary value or NULL if not found
3418 */
3419static xmlChar *
3420xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003421 xmlNodePtr node)
3422{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003423 xmlChar *ret, *escape;
3424
Daniel Veillard6eadf632003-01-23 18:29:16 +00003425 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003426 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3427 if (ret != NULL) {
3428 if (ret[0] == 0) {
3429 xmlFree(ret);
3430 return (NULL);
3431 }
3432 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3433 if (escape == NULL) {
3434 return (ret);
3435 }
3436 xmlFree(ret);
3437 return (escape);
3438 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003439 }
3440 node = node->parent;
3441 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003442 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3443 if (ret != NULL) {
3444 if (ret[0] == 0) {
3445 xmlFree(ret);
3446 return (NULL);
3447 }
3448 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3449 if (escape == NULL) {
3450 return (ret);
3451 }
3452 xmlFree(ret);
3453 return (escape);
3454 }
3455 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003456 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003457 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003458}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003459
3460/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003461 * xmlRelaxNGParseValue:
3462 * @ctxt: a Relax-NG parser context
3463 * @node: the data node.
3464 *
3465 * parse the content of a RelaxNG value node.
3466 *
3467 * Returns the definition pointer or NULL in case of error
3468 */
3469static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003470xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3471{
Daniel Veillardedc91922003-01-26 00:52:04 +00003472 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003473 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003474 xmlChar *type;
3475 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003476 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003477
Daniel Veillardfd573f12003-03-16 17:52:32 +00003478 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003479 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003480 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003481 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003482
3483 type = xmlGetProp(node, BAD_CAST "type");
3484 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003485 xmlRelaxNGNormExtSpace(type);
3486 if (xmlValidateNCName(type, 0)) {
3487 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3488 "value type '%s' is not an NCName\n", type, NULL);
3489 }
3490 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3491 if (library == NULL)
3492 library =
3493 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003494
Daniel Veillard4c004142003-10-07 11:33:24 +00003495 def->name = type;
3496 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003497
Daniel Veillard4c004142003-10-07 11:33:24 +00003498 lib = (xmlRelaxNGTypeLibraryPtr)
3499 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3500 if (lib == NULL) {
3501 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3502 "Use of unregistered type library '%s'\n", library,
3503 NULL);
3504 def->data = NULL;
3505 } else {
3506 def->data = lib;
3507 if (lib->have == NULL) {
3508 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3509 "Internal error with type library '%s': no 'have'\n",
3510 library, NULL);
3511 } else {
3512 success = lib->have(lib->data, def->name);
3513 if (success != 1) {
3514 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3515 "Error type '%s' is not exported by type library '%s'\n",
3516 def->name, library);
3517 }
3518 }
3519 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003520 }
3521 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003522 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003523 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003524 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3525 (node->children->next != NULL)) {
3526 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3527 "Expecting a single text value for <value>content\n",
3528 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003529 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003530 def->value = xmlNodeGetContent(node);
3531 if (def->value == NULL) {
3532 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3533 "Element <value> has no content\n", NULL, NULL);
3534 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3535 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003536
Daniel Veillard4c004142003-10-07 11:33:24 +00003537 success =
3538 lib->check(lib->data, def->name, def->value, &val, node);
3539 if (success != 1) {
3540 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3541 "Value '%s' is not acceptable for type '%s'\n",
3542 def->value, def->name);
3543 } else {
3544 if (val != NULL)
3545 def->attrs = val;
3546 }
3547 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003548 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003549 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003550}
3551
3552/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003553 * xmlRelaxNGParseData:
3554 * @ctxt: a Relax-NG parser context
3555 * @node: the data node.
3556 *
3557 * parse the content of a RelaxNG data node.
3558 *
3559 * Returns the definition pointer or NULL in case of error
3560 */
3561static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003562xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3563{
Daniel Veillard416589a2003-02-17 17:25:42 +00003564 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003565 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003566 xmlRelaxNGTypeLibraryPtr lib;
3567 xmlChar *type;
3568 xmlChar *library;
3569 xmlNodePtr content;
3570 int tmp;
3571
3572 type = xmlGetProp(node, BAD_CAST "type");
3573 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003574 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3575 NULL);
3576 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003577 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003578 xmlRelaxNGNormExtSpace(type);
3579 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003580 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3581 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003582 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003583 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3584 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003585 library =
3586 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003587
Daniel Veillardfd573f12003-03-16 17:52:32 +00003588 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003589 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003590 xmlFree(type);
3591 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003592 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003593 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003594 def->name = type;
3595 def->ns = library;
3596
3597 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003598 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003599 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003600 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3601 "Use of unregistered type library '%s'\n", library,
3602 NULL);
3603 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003604 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003605 def->data = lib;
3606 if (lib->have == NULL) {
3607 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3608 "Internal error with type library '%s': no 'have'\n",
3609 library, NULL);
3610 } else {
3611 tmp = lib->have(lib->data, def->name);
3612 if (tmp != 1) {
3613 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3614 "Error type '%s' is not exported by type library '%s'\n",
3615 def->name, library);
3616 } else
3617 if ((xmlStrEqual
3618 (library,
3619 BAD_CAST
3620 "http://www.w3.org/2001/XMLSchema-datatypes"))
3621 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3622 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3623 ctxt->idref = 1;
3624 }
3625 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003626 }
3627 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003628
3629 /*
3630 * Handle optional params
3631 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003632 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003633 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3634 break;
3635 if (xmlStrEqual(library,
3636 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3637 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3638 "Type library '%s' does not allow type parameters\n",
3639 library, NULL);
3640 content = content->next;
3641 while ((content != NULL) &&
3642 (xmlStrEqual(content->name, BAD_CAST "param")))
3643 content = content->next;
3644 } else {
3645 param = xmlRelaxNGNewDefine(ctxt, node);
3646 if (param != NULL) {
3647 param->type = XML_RELAXNG_PARAM;
3648 param->name = xmlGetProp(content, BAD_CAST "name");
3649 if (param->name == NULL) {
3650 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3651 "param has no name\n", NULL, NULL);
3652 }
3653 param->value = xmlNodeGetContent(content);
3654 if (lastparam == NULL) {
3655 def->attrs = lastparam = param;
3656 } else {
3657 lastparam->next = param;
3658 lastparam = param;
3659 }
3660 if (lib != NULL) {
3661 }
3662 }
3663 content = content->next;
3664 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003665 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003666 /*
3667 * Handle optional except
3668 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003669 if ((content != NULL)
3670 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3671 xmlNodePtr child;
3672 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003673
Daniel Veillard4c004142003-10-07 11:33:24 +00003674 except = xmlRelaxNGNewDefine(ctxt, node);
3675 if (except == NULL) {
3676 return (def);
3677 }
3678 except->type = XML_RELAXNG_EXCEPT;
3679 child = content->children;
3680 if (last == NULL) {
3681 def->content = except;
3682 } else {
3683 last->next = except;
3684 }
3685 if (child == NULL) {
3686 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3687 "except has no content\n", NULL, NULL);
3688 }
3689 while (child != NULL) {
3690 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3691 if (tmp2 != NULL) {
3692 if (last2 == NULL) {
3693 except->content = last2 = tmp2;
3694 } else {
3695 last2->next = tmp2;
3696 last2 = tmp2;
3697 }
3698 }
3699 child = child->next;
3700 }
3701 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003702 }
3703 /*
3704 * Check there is no unhandled data
3705 */
3706 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003707 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3708 "Element data has unexpected content %s\n",
3709 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003710 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003711
Daniel Veillard4c004142003-10-07 11:33:24 +00003712 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003713}
3714
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003715static const xmlChar *invalidName = BAD_CAST "\1";
3716
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003717/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003718 * xmlRelaxNGCompareNameClasses:
3719 * @defs1: the first element/attribute defs
3720 * @defs2: the second element/attribute defs
3721 * @name: the restriction on the name
3722 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003723 *
3724 * Compare the 2 lists of element definitions. The comparison is
3725 * that if both lists do not accept the same QNames, it returns 1
3726 * If the 2 lists can accept the same QName the comparison returns 0
3727 *
3728 * Returns 1 disttinct, 0 if equal
3729 */
3730static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003731xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003732 xmlRelaxNGDefinePtr def2)
3733{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003734 int ret = 1;
3735 xmlNode node;
3736 xmlNs ns;
3737 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003738
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003739 ctxt.flags = FLAGS_IGNORABLE;
3740
Daniel Veillard42f12e92003-03-07 18:32:59 +00003741 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3742
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003743 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003744 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3745 if (def2->type == XML_RELAXNG_TEXT)
3746 return (1);
3747 if (def1->name != NULL) {
3748 node.name = def1->name;
3749 } else {
3750 node.name = invalidName;
3751 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003752 if (def1->ns != NULL) {
3753 if (def1->ns[0] == 0) {
3754 node.ns = NULL;
3755 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003756 node.ns = &ns;
Daniel Veillard4c004142003-10-07 11:33:24 +00003757 ns.href = def1->ns;
3758 }
3759 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003760 node.ns = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00003761 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003762 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003763 if (def1->nameClass != NULL) {
3764 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3765 } else {
3766 ret = 0;
3767 }
3768 } else {
3769 ret = 1;
3770 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003771 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003772 if (def2->type == XML_RELAXNG_TEXT)
3773 return (0);
3774 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003775 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003776 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003777 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003778 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003779 }
3780 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003781 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003782 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003783 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3784 if (def2->name != NULL) {
3785 node.name = def2->name;
3786 } else {
3787 node.name = invalidName;
3788 }
3789 node.ns = &ns;
3790 if (def2->ns != NULL) {
3791 if (def2->ns[0] == 0) {
3792 node.ns = NULL;
3793 } else {
3794 ns.href = def2->ns;
3795 }
3796 } else {
3797 ns.href = invalidName;
3798 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003799 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003800 if (def2->nameClass != NULL) {
3801 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3802 } else {
3803 ret = 0;
3804 }
3805 } else {
3806 ret = 1;
3807 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003808 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003809 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003810 }
3811
Daniel Veillard4c004142003-10-07 11:33:24 +00003812 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003813}
3814
3815/**
3816 * xmlRelaxNGCompareElemDefLists:
3817 * @ctxt: a Relax-NG parser context
3818 * @defs1: the first list of element/attribute defs
3819 * @defs2: the second list of element/attribute defs
3820 *
3821 * Compare the 2 lists of element or attribute definitions. The comparison
3822 * is that if both lists do not accept the same QNames, it returns 1
3823 * If the 2 lists can accept the same QName the comparison returns 0
3824 *
3825 * Returns 1 disttinct, 0 if equal
3826 */
3827static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003828xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3829 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3830 xmlRelaxNGDefinePtr * def2)
3831{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003832 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003833
Daniel Veillard154877e2003-01-30 12:17:05 +00003834 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003835 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003836 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003837 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003838 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003839 while ((*def2) != NULL) {
3840 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3841 return (0);
3842 def2++;
3843 }
3844 def2 = basedef2;
3845 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003846 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003847 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003848}
3849
3850/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003851 * xmlRelaxNGGenerateAttributes:
3852 * @ctxt: a Relax-NG parser context
3853 * @def: the definition definition
3854 *
3855 * Check if the definition can only generate attributes
3856 *
3857 * Returns 1 if yes, 0 if no and -1 in case of error.
3858 */
3859static int
3860xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003861 xmlRelaxNGDefinePtr def)
3862{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003863 xmlRelaxNGDefinePtr parent, cur, tmp;
3864
3865 /*
3866 * Don't run that check in case of error. Infinite recursion
3867 * becomes possible.
3868 */
3869 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003870 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003871
3872 parent = NULL;
3873 cur = def;
3874 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003875 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3876 (cur->type == XML_RELAXNG_TEXT) ||
3877 (cur->type == XML_RELAXNG_DATATYPE) ||
3878 (cur->type == XML_RELAXNG_PARAM) ||
3879 (cur->type == XML_RELAXNG_LIST) ||
3880 (cur->type == XML_RELAXNG_VALUE) ||
3881 (cur->type == XML_RELAXNG_EMPTY))
3882 return (0);
3883 if ((cur->type == XML_RELAXNG_CHOICE) ||
3884 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3885 (cur->type == XML_RELAXNG_GROUP) ||
3886 (cur->type == XML_RELAXNG_ONEORMORE) ||
3887 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3888 (cur->type == XML_RELAXNG_OPTIONAL) ||
3889 (cur->type == XML_RELAXNG_PARENTREF) ||
3890 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3891 (cur->type == XML_RELAXNG_REF) ||
3892 (cur->type == XML_RELAXNG_DEF)) {
3893 if (cur->content != NULL) {
3894 parent = cur;
3895 cur = cur->content;
3896 tmp = cur;
3897 while (tmp != NULL) {
3898 tmp->parent = parent;
3899 tmp = tmp->next;
3900 }
3901 continue;
3902 }
3903 }
3904 if (cur == def)
3905 break;
3906 if (cur->next != NULL) {
3907 cur = cur->next;
3908 continue;
3909 }
3910 do {
3911 cur = cur->parent;
3912 if (cur == NULL)
3913 break;
3914 if (cur == def)
3915 return (1);
3916 if (cur->next != NULL) {
3917 cur = cur->next;
3918 break;
3919 }
3920 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003921 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003922 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003923}
Daniel Veillard4c004142003-10-07 11:33:24 +00003924
Daniel Veillardce192eb2003-04-16 15:58:05 +00003925/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003926 * xmlRelaxNGGetElements:
3927 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003928 * @def: the definition definition
3929 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003930 *
3931 * Compute the list of top elements a definition can generate
3932 *
3933 * Returns a list of elements or NULL if none was found.
3934 */
3935static xmlRelaxNGDefinePtr *
3936xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003937 xmlRelaxNGDefinePtr def, int eora)
3938{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003939 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003940 int len = 0;
3941 int max = 0;
3942
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003943 /*
3944 * Don't run that check in case of error. Infinite recursion
3945 * becomes possible.
3946 */
3947 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003948 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003949
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003950 parent = NULL;
3951 cur = def;
3952 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003953 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3954 (cur->type == XML_RELAXNG_TEXT))) ||
3955 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3956 if (ret == NULL) {
3957 max = 10;
3958 ret = (xmlRelaxNGDefinePtr *)
3959 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3960 if (ret == NULL) {
3961 xmlRngPErrMemory(ctxt, "getting element list\n");
3962 return (NULL);
3963 }
3964 } else if (max <= len) {
Daniel Veillard079f6a72004-09-23 13:15:03 +00003965 xmlRelaxNGDefinePtr *temp;
3966
Daniel Veillard4c004142003-10-07 11:33:24 +00003967 max *= 2;
Daniel Veillard079f6a72004-09-23 13:15:03 +00003968 temp = xmlRealloc(ret,
Daniel Veillard4c004142003-10-07 11:33:24 +00003969 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
Daniel Veillard079f6a72004-09-23 13:15:03 +00003970 if (temp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003971 xmlRngPErrMemory(ctxt, "getting element list\n");
Daniel Veillard079f6a72004-09-23 13:15:03 +00003972 xmlFree(ret);
Daniel Veillard4c004142003-10-07 11:33:24 +00003973 return (NULL);
3974 }
Daniel Veillard079f6a72004-09-23 13:15:03 +00003975 ret = temp;
Daniel Veillard4c004142003-10-07 11:33:24 +00003976 }
3977 ret[len++] = cur;
3978 ret[len] = NULL;
3979 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3980 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3981 (cur->type == XML_RELAXNG_GROUP) ||
3982 (cur->type == XML_RELAXNG_ONEORMORE) ||
3983 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3984 (cur->type == XML_RELAXNG_OPTIONAL) ||
3985 (cur->type == XML_RELAXNG_PARENTREF) ||
3986 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00003987 (cur->type == XML_RELAXNG_DEF) ||
3988 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003989 /*
3990 * Don't go within elements or attributes or string values.
3991 * Just gather the element top list
3992 */
3993 if (cur->content != NULL) {
3994 parent = cur;
3995 cur = cur->content;
3996 tmp = cur;
3997 while (tmp != NULL) {
3998 tmp->parent = parent;
3999 tmp = tmp->next;
4000 }
4001 continue;
4002 }
4003 }
4004 if (cur == def)
4005 break;
4006 if (cur->next != NULL) {
4007 cur = cur->next;
4008 continue;
4009 }
4010 do {
4011 cur = cur->parent;
4012 if (cur == NULL)
4013 break;
4014 if (cur == def)
4015 return (ret);
4016 if (cur->next != NULL) {
4017 cur = cur->next;
4018 break;
4019 }
4020 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004021 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004022 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004023}
Daniel Veillard4c004142003-10-07 11:33:24 +00004024
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004025/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004026 * xmlRelaxNGCheckChoiceDeterminism:
4027 * @ctxt: a Relax-NG parser context
4028 * @def: the choice definition
4029 *
4030 * Also used to find indeterministic pattern in choice
4031 */
4032static void
4033xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004034 xmlRelaxNGDefinePtr def)
4035{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004036 xmlRelaxNGDefinePtr **list;
4037 xmlRelaxNGDefinePtr cur;
4038 int nbchild = 0, i, j, ret;
4039 int is_nullable = 0;
4040 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004041 xmlHashTablePtr triage = NULL;
4042 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004043
Daniel Veillard4c004142003-10-07 11:33:24 +00004044 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4045 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004046
Daniel Veillarde063f482003-03-21 16:53:17 +00004047 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004048 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004049
Daniel Veillardfd573f12003-03-16 17:52:32 +00004050 /*
4051 * Don't run that check in case of error. Infinite recursion
4052 * becomes possible.
4053 */
4054 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004055 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004056
4057 is_nullable = xmlRelaxNGIsNullable(def);
4058
4059 cur = def->content;
4060 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004061 nbchild++;
4062 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004063 }
4064
4065 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004066 sizeof(xmlRelaxNGDefinePtr
4067 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004068 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004069 xmlRngPErrMemory(ctxt, "building choice\n");
4070 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004071 }
4072 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004073 /*
4074 * a bit strong but safe
4075 */
4076 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004077 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004078 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004079 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004080 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004081 cur = def->content;
4082 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004083 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4084 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4085 is_triable = 0;
4086 } else if (is_triable == 1) {
4087 xmlRelaxNGDefinePtr *tmp;
4088 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004089
Daniel Veillard4c004142003-10-07 11:33:24 +00004090 tmp = list[i];
4091 while ((*tmp != NULL) && (is_triable == 1)) {
4092 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4093 res = xmlHashAddEntry2(triage,
4094 BAD_CAST "#text", NULL,
4095 (void *) cur);
4096 if (res != 0)
4097 is_triable = -1;
4098 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4099 ((*tmp)->name != NULL)) {
4100 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4101 res = xmlHashAddEntry2(triage,
4102 (*tmp)->name, NULL,
4103 (void *) cur);
4104 else
4105 res = xmlHashAddEntry2(triage,
4106 (*tmp)->name, (*tmp)->ns,
4107 (void *) cur);
4108 if (res != 0)
4109 is_triable = -1;
4110 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4111 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4112 res = xmlHashAddEntry2(triage,
4113 BAD_CAST "#any", NULL,
4114 (void *) cur);
4115 else
4116 res = xmlHashAddEntry2(triage,
4117 BAD_CAST "#any", (*tmp)->ns,
4118 (void *) cur);
4119 if (res != 0)
4120 is_triable = -1;
4121 } else {
4122 is_triable = -1;
4123 }
4124 tmp++;
4125 }
4126 }
4127 i++;
4128 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004129 }
4130
Daniel Veillard4c004142003-10-07 11:33:24 +00004131 for (i = 0; i < nbchild; i++) {
4132 if (list[i] == NULL)
4133 continue;
4134 for (j = 0; j < i; j++) {
4135 if (list[j] == NULL)
4136 continue;
4137 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4138 if (ret == 0) {
4139 is_indeterminist = 1;
4140 }
4141 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004142 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004143 for (i = 0; i < nbchild; i++) {
4144 if (list[i] != NULL)
4145 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004146 }
4147
4148 xmlFree(list);
4149 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004150 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004151 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004152 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004153 def->dflags |= IS_TRIABLE;
4154 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004155 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004156 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004157 }
4158 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004159}
4160
4161/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004162 * xmlRelaxNGCheckGroupAttrs:
4163 * @ctxt: a Relax-NG parser context
4164 * @def: the group definition
4165 *
4166 * Detects violations of rule 7.3
4167 */
4168static void
4169xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004170 xmlRelaxNGDefinePtr def)
4171{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004172 xmlRelaxNGDefinePtr **list;
4173 xmlRelaxNGDefinePtr cur;
4174 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004175
4176 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004177 ((def->type != XML_RELAXNG_GROUP) &&
4178 (def->type != XML_RELAXNG_ELEMENT)))
4179 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004180
Daniel Veillarde063f482003-03-21 16:53:17 +00004181 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004182 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004183
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004184 /*
4185 * Don't run that check in case of error. Infinite recursion
4186 * becomes possible.
4187 */
4188 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004189 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004190
Daniel Veillardfd573f12003-03-16 17:52:32 +00004191 cur = def->attrs;
4192 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004193 nbchild++;
4194 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004195 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004196 cur = def->content;
4197 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004198 nbchild++;
4199 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004200 }
4201
4202 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004203 sizeof(xmlRelaxNGDefinePtr
4204 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004205 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004206 xmlRngPErrMemory(ctxt, "building group\n");
4207 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004208 }
4209 i = 0;
4210 cur = def->attrs;
4211 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004212 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4213 i++;
4214 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004215 }
4216 cur = def->content;
4217 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004218 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4219 i++;
4220 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004221 }
4222
Daniel Veillard4c004142003-10-07 11:33:24 +00004223 for (i = 0; i < nbchild; i++) {
4224 if (list[i] == NULL)
4225 continue;
4226 for (j = 0; j < i; j++) {
4227 if (list[j] == NULL)
4228 continue;
4229 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4230 if (ret == 0) {
4231 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4232 "Attributes conflicts in group\n", NULL, NULL);
4233 }
4234 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004235 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004236 for (i = 0; i < nbchild; i++) {
4237 if (list[i] != NULL)
4238 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004239 }
4240
4241 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004242 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004243}
4244
4245/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004246 * xmlRelaxNGComputeInterleaves:
4247 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004248 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004249 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004250 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004251 * A lot of work for preprocessing interleave definitions
4252 * is potentially needed to get a decent execution speed at runtime
4253 * - trying to get a total order on the element nodes generated
4254 * by the interleaves, order the list of interleave definitions
4255 * following that order.
4256 * - if <text/> is used to handle mixed content, it is better to
4257 * flag this in the define and simplify the runtime checking
4258 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004259 */
4260static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004261xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004262 xmlRelaxNGParserCtxtPtr ctxt,
4263 xmlChar * name ATTRIBUTE_UNUSED)
4264{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004265 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004266
Daniel Veillardfd573f12003-03-16 17:52:32 +00004267 xmlRelaxNGPartitionPtr partitions = NULL;
4268 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4269 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004270 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004271 int nbgroups = 0;
4272 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004273 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004274 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004275
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004276 /*
4277 * Don't run that check in case of error. Infinite recursion
4278 * becomes possible.
4279 */
4280 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004281 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004282
Daniel Veillardfd573f12003-03-16 17:52:32 +00004283#ifdef DEBUG_INTERLEAVE
4284 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004285 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004286#endif
4287 cur = def->content;
4288 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004289 nbchild++;
4290 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004291 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004292
Daniel Veillardfd573f12003-03-16 17:52:32 +00004293#ifdef DEBUG_INTERLEAVE
4294 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4295#endif
4296 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004297 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004298 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004299 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004300 cur = def->content;
4301 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004302 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4303 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4304 if (groups[nbgroups] == NULL)
4305 goto error;
4306 if (cur->type == XML_RELAXNG_TEXT)
4307 is_mixed++;
4308 groups[nbgroups]->rule = cur;
4309 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4310 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4311 nbgroups++;
4312 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004313 }
4314#ifdef DEBUG_INTERLEAVE
4315 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4316#endif
4317
4318 /*
4319 * Let's check that all rules makes a partitions according to 7.4
4320 */
4321 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004322 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004323 if (partitions == NULL)
4324 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004325 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004326 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004327 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004328 for (i = 0; i < nbgroups; i++) {
4329 group = groups[i];
4330 for (j = i + 1; j < nbgroups; j++) {
4331 if (groups[j] == NULL)
4332 continue;
4333
4334 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4335 groups[j]->defs);
4336 if (ret == 0) {
4337 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4338 "Element or text conflicts in interleave\n",
4339 NULL, NULL);
4340 }
4341 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4342 groups[j]->attrs);
4343 if (ret == 0) {
4344 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4345 "Attributes conflicts in interleave\n", NULL,
4346 NULL);
4347 }
4348 }
4349 tmp = group->defs;
4350 if ((tmp != NULL) && (*tmp != NULL)) {
4351 while (*tmp != NULL) {
4352 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4353 res = xmlHashAddEntry2(partitions->triage,
4354 BAD_CAST "#text", NULL,
4355 (void *) (long) (i + 1));
4356 if (res != 0)
4357 is_determinist = -1;
4358 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4359 ((*tmp)->name != NULL)) {
4360 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4361 res = xmlHashAddEntry2(partitions->triage,
4362 (*tmp)->name, NULL,
4363 (void *) (long) (i + 1));
4364 else
4365 res = xmlHashAddEntry2(partitions->triage,
4366 (*tmp)->name, (*tmp)->ns,
4367 (void *) (long) (i + 1));
4368 if (res != 0)
4369 is_determinist = -1;
4370 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4371 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4372 res = xmlHashAddEntry2(partitions->triage,
4373 BAD_CAST "#any", NULL,
4374 (void *) (long) (i + 1));
4375 else
4376 res = xmlHashAddEntry2(partitions->triage,
4377 BAD_CAST "#any", (*tmp)->ns,
4378 (void *) (long) (i + 1));
4379 if ((*tmp)->nameClass != NULL)
4380 is_determinist = 2;
4381 if (res != 0)
4382 is_determinist = -1;
4383 } else {
4384 is_determinist = -1;
4385 }
4386 tmp++;
4387 }
4388 } else {
4389 is_determinist = 0;
4390 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004391 }
4392 partitions->groups = groups;
4393
4394 /*
4395 * and save the partition list back in the def
4396 */
4397 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004398 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004399 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004400 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004401 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004402 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004403 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004404 return;
4405
Daniel Veillard4c004142003-10-07 11:33:24 +00004406 error:
4407 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004408 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004409 for (i = 0; i < nbgroups; i++)
4410 if (groups[i] != NULL) {
4411 if (groups[i]->defs != NULL)
4412 xmlFree(groups[i]->defs);
4413 xmlFree(groups[i]);
4414 }
4415 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004416 }
4417 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004418}
4419
4420/**
4421 * xmlRelaxNGParseInterleave:
4422 * @ctxt: a Relax-NG parser context
4423 * @node: the data node.
4424 *
4425 * parse the content of a RelaxNG interleave node.
4426 *
4427 * Returns the definition pointer or NULL in case of error
4428 */
4429static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004430xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4431{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004432 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004433 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004434 xmlNodePtr child;
4435
Daniel Veillardfd573f12003-03-16 17:52:32 +00004436 def = xmlRelaxNGNewDefine(ctxt, node);
4437 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004438 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004439 }
4440 def->type = XML_RELAXNG_INTERLEAVE;
4441
4442 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004443 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004444 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004445 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004446 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004447 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004448
Daniel Veillard4c004142003-10-07 11:33:24 +00004449 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4450 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4451 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4452 "Failed to add %s to hash table\n",
4453 (const xmlChar *) name, NULL);
4454 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004455 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004456 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004457 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004458 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4459 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004460 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004461 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004462 if (IS_RELAXNG(child, "element")) {
4463 cur = xmlRelaxNGParseElement(ctxt, child);
4464 } else {
4465 cur = xmlRelaxNGParsePattern(ctxt, child);
4466 }
4467 if (cur != NULL) {
4468 cur->parent = def;
4469 if (last == NULL) {
4470 def->content = last = cur;
4471 } else {
4472 last->next = cur;
4473 last = cur;
4474 }
4475 }
4476 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004477 }
4478
Daniel Veillard4c004142003-10-07 11:33:24 +00004479 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004480}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004481
4482/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004483 * xmlRelaxNGParseInclude:
4484 * @ctxt: a Relax-NG parser context
4485 * @node: the include node
4486 *
4487 * Integrate the content of an include node in the current grammar
4488 *
4489 * Returns 0 in case of success or -1 in case of error
4490 */
4491static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004492xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4493{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004494 xmlRelaxNGIncludePtr incl;
4495 xmlNodePtr root;
4496 int ret = 0, tmp;
4497
Daniel Veillard807daf82004-02-22 22:13:27 +00004498 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004499 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004500 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4501 "Include node has no data\n", NULL, NULL);
4502 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004503 }
4504 root = xmlDocGetRootElement(incl->doc);
4505 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004506 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4507 NULL, NULL);
4508 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004509 }
4510 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004511 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4512 "Include document root is not a grammar\n", NULL, NULL);
4513 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004514 }
4515
4516 /*
4517 * Merge the definition from both the include and the internal list
4518 */
4519 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004520 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4521 if (tmp != 0)
4522 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004523 }
4524 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004525 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4526 if (tmp != 0)
4527 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004528 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004529 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004530}
4531
4532/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004533 * xmlRelaxNGParseDefine:
4534 * @ctxt: a Relax-NG parser context
4535 * @node: the define node
4536 *
4537 * parse the content of a RelaxNG define element node.
4538 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004539 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004540 */
4541static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004542xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4543{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004544 xmlChar *name;
4545 int ret = 0, tmp;
4546 xmlRelaxNGDefinePtr def;
4547 const xmlChar *olddefine;
4548
4549 name = xmlGetProp(node, BAD_CAST "name");
4550 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004551 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4552 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004553 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004554 xmlRelaxNGNormExtSpace(name);
4555 if (xmlValidateNCName(name, 0)) {
4556 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4557 "define name '%s' is not an NCName\n", name, NULL);
4558 }
4559 def = xmlRelaxNGNewDefine(ctxt, node);
4560 if (def == NULL) {
4561 xmlFree(name);
4562 return (-1);
4563 }
4564 def->type = XML_RELAXNG_DEF;
4565 def->name = name;
4566 if (node->children == NULL) {
4567 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4568 "define has no children\n", NULL, NULL);
4569 } else {
4570 olddefine = ctxt->define;
4571 ctxt->define = name;
4572 def->content =
4573 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4574 ctxt->define = olddefine;
4575 }
4576 if (ctxt->grammar->defs == NULL)
4577 ctxt->grammar->defs = xmlHashCreate(10);
4578 if (ctxt->grammar->defs == NULL) {
4579 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4580 "Could not create definition hash\n", NULL, NULL);
4581 ret = -1;
4582 } else {
4583 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4584 if (tmp < 0) {
4585 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004586
Daniel Veillard4c004142003-10-07 11:33:24 +00004587 prev = xmlHashLookup(ctxt->grammar->defs, name);
4588 if (prev == NULL) {
4589 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4590 "Internal error on define aggregation of %s\n",
4591 name, NULL);
4592 ret = -1;
4593 } else {
4594 while (prev->nextHash != NULL)
4595 prev = prev->nextHash;
4596 prev->nextHash = def;
4597 }
4598 }
4599 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004600 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004601 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004602}
4603
4604/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004605 * xmlRelaxNGProcessExternalRef:
4606 * @ctxt: the parser context
4607 * @node: the externlRef node
4608 *
4609 * Process and compile an externlRef node
4610 *
4611 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4612 */
4613static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004614xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4615{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004616 xmlRelaxNGDocumentPtr docu;
4617 xmlNodePtr root, tmp;
4618 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004619 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004620 xmlRelaxNGDefinePtr def;
4621
Daniel Veillard807daf82004-02-22 22:13:27 +00004622 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004623 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004624 def = xmlRelaxNGNewDefine(ctxt, node);
4625 if (def == NULL)
4626 return (NULL);
4627 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004628
Daniel Veillard4c004142003-10-07 11:33:24 +00004629 if (docu->content == NULL) {
4630 /*
4631 * Then do the parsing for good
4632 */
4633 root = xmlDocGetRootElement(docu->doc);
4634 if (root == NULL) {
4635 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4636 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4637 NULL);
4638 return (NULL);
4639 }
4640 /*
4641 * ns transmission rules
4642 */
4643 ns = xmlGetProp(root, BAD_CAST "ns");
4644 if (ns == NULL) {
4645 tmp = node;
4646 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4647 ns = xmlGetProp(tmp, BAD_CAST "ns");
4648 if (ns != NULL) {
4649 break;
4650 }
4651 tmp = tmp->parent;
4652 }
4653 if (ns != NULL) {
4654 xmlSetProp(root, BAD_CAST "ns", ns);
4655 newNs = 1;
4656 xmlFree(ns);
4657 }
4658 } else {
4659 xmlFree(ns);
4660 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004661
Daniel Veillard4c004142003-10-07 11:33:24 +00004662 /*
4663 * Parsing to get a precompiled schemas.
4664 */
4665 oldflags = ctxt->flags;
4666 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4667 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4668 ctxt->flags = oldflags;
4669 if ((docu->schema != NULL) &&
4670 (docu->schema->topgrammar != NULL)) {
4671 docu->content = docu->schema->topgrammar->start;
4672 }
4673
4674 /*
4675 * the externalRef may be reused in a different ns context
4676 */
4677 if (newNs == 1) {
4678 xmlUnsetProp(root, BAD_CAST "ns");
4679 }
4680 }
4681 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004682 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004683 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004684 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004685 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004686}
4687
4688/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004689 * xmlRelaxNGParsePattern:
4690 * @ctxt: a Relax-NG parser context
4691 * @node: the pattern node.
4692 *
4693 * parse the content of a RelaxNG pattern node.
4694 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004695 * Returns the definition pointer or NULL in case of error or if no
4696 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004697 */
4698static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004699xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4700{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004701 xmlRelaxNGDefinePtr def = NULL;
4702
Daniel Veillardd2298792003-02-14 16:54:11 +00004703 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004704 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004705 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004706 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004707 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004708 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004709 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004710 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004711 def = xmlRelaxNGNewDefine(ctxt, node);
4712 if (def == NULL)
4713 return (NULL);
4714 def->type = XML_RELAXNG_EMPTY;
4715 if (node->children != NULL) {
4716 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4717 "empty: had a child node\n", NULL, NULL);
4718 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004719 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004720 def = xmlRelaxNGNewDefine(ctxt, node);
4721 if (def == NULL)
4722 return (NULL);
4723 def->type = XML_RELAXNG_TEXT;
4724 if (node->children != NULL) {
4725 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4726 "text: had a child node\n", NULL, NULL);
4727 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004728 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004729 def = xmlRelaxNGNewDefine(ctxt, node);
4730 if (def == NULL)
4731 return (NULL);
4732 def->type = XML_RELAXNG_ZEROORMORE;
4733 if (node->children == NULL) {
4734 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4735 "Element %s is empty\n", node->name, NULL);
4736 } else {
4737 def->content =
4738 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4739 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004740 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004741 def = xmlRelaxNGNewDefine(ctxt, node);
4742 if (def == NULL)
4743 return (NULL);
4744 def->type = XML_RELAXNG_ONEORMORE;
4745 if (node->children == NULL) {
4746 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4747 "Element %s is empty\n", node->name, NULL);
4748 } else {
4749 def->content =
4750 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4751 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004752 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004753 def = xmlRelaxNGNewDefine(ctxt, node);
4754 if (def == NULL)
4755 return (NULL);
4756 def->type = XML_RELAXNG_OPTIONAL;
4757 if (node->children == NULL) {
4758 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4759 "Element %s is empty\n", node->name, NULL);
4760 } else {
4761 def->content =
4762 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4763 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004764 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004765 def = xmlRelaxNGNewDefine(ctxt, node);
4766 if (def == NULL)
4767 return (NULL);
4768 def->type = XML_RELAXNG_CHOICE;
4769 if (node->children == NULL) {
4770 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4771 "Element %s is empty\n", node->name, NULL);
4772 } else {
4773 def->content =
4774 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4775 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004776 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004777 def = xmlRelaxNGNewDefine(ctxt, node);
4778 if (def == NULL)
4779 return (NULL);
4780 def->type = XML_RELAXNG_GROUP;
4781 if (node->children == NULL) {
4782 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4783 "Element %s is empty\n", node->name, NULL);
4784 } else {
4785 def->content =
4786 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4787 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004788 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004789 def = xmlRelaxNGNewDefine(ctxt, node);
4790 if (def == NULL)
4791 return (NULL);
4792 def->type = XML_RELAXNG_REF;
4793 def->name = xmlGetProp(node, BAD_CAST "name");
4794 if (def->name == NULL) {
4795 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4796 NULL, NULL);
4797 } else {
4798 xmlRelaxNGNormExtSpace(def->name);
4799 if (xmlValidateNCName(def->name, 0)) {
4800 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4801 "ref name '%s' is not an NCName\n", def->name,
4802 NULL);
4803 }
4804 }
4805 if (node->children != NULL) {
4806 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4807 NULL, NULL);
4808 }
4809 if (ctxt->grammar->refs == NULL)
4810 ctxt->grammar->refs = xmlHashCreate(10);
4811 if (ctxt->grammar->refs == NULL) {
4812 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4813 "Could not create references hash\n", NULL, NULL);
4814 def = NULL;
4815 } else {
4816 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004817
Daniel Veillard4c004142003-10-07 11:33:24 +00004818 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4819 if (tmp < 0) {
4820 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004821
Daniel Veillard4c004142003-10-07 11:33:24 +00004822 prev = (xmlRelaxNGDefinePtr)
4823 xmlHashLookup(ctxt->grammar->refs, def->name);
4824 if (prev == NULL) {
4825 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004826 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4827 "Error refs definitions '%s'\n",
4828 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004829 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004830 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4831 "Error refs definitions\n",
4832 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004833 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004834 def = NULL;
4835 } else {
4836 def->nextHash = prev->nextHash;
4837 prev->nextHash = def;
4838 }
4839 }
4840 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004841 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004842 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004843 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004844 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004845 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004846 def = xmlRelaxNGNewDefine(ctxt, node);
4847 if (def == NULL)
4848 return (NULL);
4849 def->type = XML_RELAXNG_LIST;
4850 if (node->children == NULL) {
4851 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4852 "Element %s is empty\n", node->name, NULL);
4853 } else {
4854 def->content =
4855 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4856 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004857 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004858 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004859 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004860 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004861 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004862 def = xmlRelaxNGNewDefine(ctxt, node);
4863 if (def == NULL)
4864 return (NULL);
4865 def->type = XML_RELAXNG_NOT_ALLOWED;
4866 if (node->children != NULL) {
4867 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4868 "xmlRelaxNGParse: notAllowed element is not empty\n",
4869 NULL, NULL);
4870 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004871 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004872 xmlRelaxNGGrammarPtr grammar, old;
4873 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004874
Daniel Veillardc482e262003-02-26 14:48:48 +00004875#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004876 xmlGenericError(xmlGenericErrorContext,
4877 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004878#endif
4879
Daniel Veillard4c004142003-10-07 11:33:24 +00004880 oldparent = ctxt->parentgrammar;
4881 old = ctxt->grammar;
4882 ctxt->parentgrammar = old;
4883 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4884 if (old != NULL) {
4885 ctxt->grammar = old;
4886 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004887#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004888 if (grammar != NULL) {
4889 grammar->next = old->next;
4890 old->next = grammar;
4891 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004892#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004893 }
4894 if (grammar != NULL)
4895 def = grammar->start;
4896 else
4897 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004898 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004899 if (ctxt->parentgrammar == NULL) {
4900 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4901 "Use of parentRef without a parent grammar\n", NULL,
4902 NULL);
4903 return (NULL);
4904 }
4905 def = xmlRelaxNGNewDefine(ctxt, node);
4906 if (def == NULL)
4907 return (NULL);
4908 def->type = XML_RELAXNG_PARENTREF;
4909 def->name = xmlGetProp(node, BAD_CAST "name");
4910 if (def->name == NULL) {
4911 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4912 "parentRef has no name\n", NULL, NULL);
4913 } else {
4914 xmlRelaxNGNormExtSpace(def->name);
4915 if (xmlValidateNCName(def->name, 0)) {
4916 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4917 "parentRef name '%s' is not an NCName\n",
4918 def->name, NULL);
4919 }
4920 }
4921 if (node->children != NULL) {
4922 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4923 "parentRef is not empty\n", NULL, NULL);
4924 }
4925 if (ctxt->parentgrammar->refs == NULL)
4926 ctxt->parentgrammar->refs = xmlHashCreate(10);
4927 if (ctxt->parentgrammar->refs == NULL) {
4928 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4929 "Could not create references hash\n", NULL, NULL);
4930 def = NULL;
4931 } else if (def->name != NULL) {
4932 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004933
Daniel Veillard4c004142003-10-07 11:33:24 +00004934 tmp =
4935 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4936 if (tmp < 0) {
4937 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004938
Daniel Veillard4c004142003-10-07 11:33:24 +00004939 prev = (xmlRelaxNGDefinePtr)
4940 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4941 if (prev == NULL) {
4942 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4943 "Internal error parentRef definitions '%s'\n",
4944 def->name, NULL);
4945 def = NULL;
4946 } else {
4947 def->nextHash = prev->nextHash;
4948 prev->nextHash = def;
4949 }
4950 }
4951 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004952 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004953 if (node->children == NULL) {
4954 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4955 NULL, NULL);
4956 def = NULL;
4957 } else {
4958 def = xmlRelaxNGParseInterleave(ctxt, node);
4959 if (def != NULL) {
4960 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004961
Daniel Veillard4c004142003-10-07 11:33:24 +00004962 if ((def->content != NULL) && (def->content->next != NULL)) {
4963 tmp = xmlRelaxNGNewDefine(ctxt, node);
4964 if (tmp != NULL) {
4965 tmp->type = XML_RELAXNG_GROUP;
4966 tmp->content = def->content;
4967 def->content = tmp;
4968 }
4969 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004970
Daniel Veillard4c004142003-10-07 11:33:24 +00004971 tmp = xmlRelaxNGNewDefine(ctxt, node);
4972 if (tmp == NULL)
4973 return (def);
4974 tmp->type = XML_RELAXNG_TEXT;
4975 tmp->next = def->content;
4976 def->content = tmp;
4977 }
4978 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004979 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004980 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4981 "Unexpected node %s is not a pattern\n", node->name,
4982 NULL);
4983 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004984 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004985 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004986}
4987
4988/**
4989 * xmlRelaxNGParseAttribute:
4990 * @ctxt: a Relax-NG parser context
4991 * @node: the element node
4992 *
4993 * parse the content of a RelaxNG attribute node.
4994 *
4995 * Returns the definition pointer or NULL in case of error.
4996 */
4997static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004998xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4999{
Daniel Veillardd2298792003-02-14 16:54:11 +00005000 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005001 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005002 int old_flags;
5003
Daniel Veillardfd573f12003-03-16 17:52:32 +00005004 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005005 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005006 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005007 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005008 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005009 child = node->children;
5010 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005011 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5012 "xmlRelaxNGParseattribute: attribute has no children\n",
5013 NULL, NULL);
5014 return (ret);
5015 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005016 old_flags = ctxt->flags;
5017 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005018 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5019 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005020 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005021
Daniel Veillardd2298792003-02-14 16:54:11 +00005022 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005023 cur = xmlRelaxNGParsePattern(ctxt, child);
5024 if (cur != NULL) {
5025 switch (cur->type) {
5026 case XML_RELAXNG_EMPTY:
5027 case XML_RELAXNG_NOT_ALLOWED:
5028 case XML_RELAXNG_TEXT:
5029 case XML_RELAXNG_ELEMENT:
5030 case XML_RELAXNG_DATATYPE:
5031 case XML_RELAXNG_VALUE:
5032 case XML_RELAXNG_LIST:
5033 case XML_RELAXNG_REF:
5034 case XML_RELAXNG_PARENTREF:
5035 case XML_RELAXNG_EXTERNALREF:
5036 case XML_RELAXNG_DEF:
5037 case XML_RELAXNG_ONEORMORE:
5038 case XML_RELAXNG_ZEROORMORE:
5039 case XML_RELAXNG_OPTIONAL:
5040 case XML_RELAXNG_CHOICE:
5041 case XML_RELAXNG_GROUP:
5042 case XML_RELAXNG_INTERLEAVE:
5043 case XML_RELAXNG_ATTRIBUTE:
5044 ret->content = cur;
5045 cur->parent = ret;
5046 break;
5047 case XML_RELAXNG_START:
5048 case XML_RELAXNG_PARAM:
5049 case XML_RELAXNG_EXCEPT:
5050 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5051 "attribute has invalid content\n", NULL,
5052 NULL);
5053 break;
5054 case XML_RELAXNG_NOOP:
5055 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5056 "RNG Internal error, noop found in attribute\n",
5057 NULL, NULL);
5058 break;
5059 }
5060 }
5061 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005062 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005063 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005064 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5065 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005066 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005067 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005068 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005069}
5070
5071/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005072 * xmlRelaxNGParseExceptNameClass:
5073 * @ctxt: a Relax-NG parser context
5074 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005075 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005076 *
5077 * parse the content of a RelaxNG nameClass node.
5078 *
5079 * Returns the definition pointer or NULL in case of error.
5080 */
5081static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005082xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005083 xmlNodePtr node, int attr)
5084{
Daniel Veillard144fae12003-02-03 13:17:57 +00005085 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5086 xmlNodePtr child;
5087
Daniel Veillardd2298792003-02-14 16:54:11 +00005088 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005089 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5090 "Expecting an except node\n", NULL, NULL);
5091 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005092 }
5093 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005094 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5095 "exceptNameClass allows only a single except node\n",
5096 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005097 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005098 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005099 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5100 NULL, NULL);
5101 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005102 }
5103
Daniel Veillardfd573f12003-03-16 17:52:32 +00005104 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005105 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005106 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005107 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005108 child = node->children;
5109 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005110 cur = xmlRelaxNGNewDefine(ctxt, child);
5111 if (cur == NULL)
5112 break;
5113 if (attr)
5114 cur->type = XML_RELAXNG_ATTRIBUTE;
5115 else
5116 cur->type = XML_RELAXNG_ELEMENT;
5117
Daniel Veillard419a7682003-02-03 23:22:49 +00005118 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005119 if (last == NULL) {
5120 ret->content = cur;
5121 } else {
5122 last->next = cur;
5123 }
5124 last = cur;
5125 }
5126 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005127 }
5128
Daniel Veillard4c004142003-10-07 11:33:24 +00005129 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005130}
5131
5132/**
5133 * xmlRelaxNGParseNameClass:
5134 * @ctxt: a Relax-NG parser context
5135 * @node: the nameClass node
5136 * @def: the current definition
5137 *
5138 * parse the content of a RelaxNG nameClass node.
5139 *
5140 * Returns the definition pointer or NULL in case of error.
5141 */
5142static xmlRelaxNGDefinePtr
5143xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005144 xmlRelaxNGDefinePtr def)
5145{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005146 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005147 xmlChar *val;
5148
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005149 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005150 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005151 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005152 if ((def->type != XML_RELAXNG_ELEMENT) &&
5153 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5154 ret = xmlRelaxNGNewDefine(ctxt, node);
5155 if (ret == NULL)
5156 return (NULL);
5157 ret->parent = def;
5158 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5159 ret->type = XML_RELAXNG_ATTRIBUTE;
5160 else
5161 ret->type = XML_RELAXNG_ELEMENT;
5162 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005163 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005164 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005165 val = xmlNodeGetContent(node);
5166 xmlRelaxNGNormExtSpace(val);
5167 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005168 if (node->parent != NULL)
5169 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5170 "Element %s name '%s' is not an NCName\n",
5171 node->parent->name, val);
5172 else
5173 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5174 "name '%s' is not an NCName\n",
5175 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005176 }
5177 ret->name = val;
5178 val = xmlGetProp(node, BAD_CAST "ns");
5179 ret->ns = val;
5180 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5181 (val != NULL) &&
5182 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005183 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005184 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005185 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005186 }
5187 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5188 (val != NULL) &&
5189 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005190 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5191 "Attribute with QName 'xmlns' is not allowed\n",
5192 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005193 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005194 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005195 ret->name = NULL;
5196 ret->ns = NULL;
5197 if (node->children != NULL) {
5198 ret->nameClass =
5199 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5200 (def->type ==
5201 XML_RELAXNG_ATTRIBUTE));
5202 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005203 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005204 ret->name = NULL;
5205 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5206 if (ret->ns == NULL) {
5207 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5208 "nsName has no ns attribute\n", NULL, NULL);
5209 }
5210 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5211 (ret->ns != NULL) &&
5212 (xmlStrEqual
5213 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5214 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5215 "Attribute with namespace '%s' is not allowed\n",
5216 ret->ns, NULL);
5217 }
5218 if (node->children != NULL) {
5219 ret->nameClass =
5220 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5221 (def->type ==
5222 XML_RELAXNG_ATTRIBUTE));
5223 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005224 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005225 xmlNodePtr child;
5226 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005227
Daniel Veillard4c004142003-10-07 11:33:24 +00005228 ret = xmlRelaxNGNewDefine(ctxt, node);
5229 if (ret == NULL)
5230 return (NULL);
5231 ret->parent = def;
5232 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005233
Daniel Veillard4c004142003-10-07 11:33:24 +00005234 if (node->children == NULL) {
5235 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5236 "Element choice is empty\n", NULL, NULL);
5237 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005238
Daniel Veillard4c004142003-10-07 11:33:24 +00005239 child = node->children;
5240 while (child != NULL) {
5241 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5242 if (tmp != NULL) {
5243 if (last == NULL) {
5244 last = ret->nameClass = tmp;
5245 } else {
5246 last->next = tmp;
5247 last = tmp;
5248 }
5249 }
5250 child = child->next;
5251 }
5252 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005253 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005254 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5255 "expecting name, anyName, nsName or choice : got %s\n",
5256 node->name, NULL);
5257 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005258 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005259 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005260 if (def->nameClass == NULL) {
5261 def->nameClass = ret;
5262 } else {
5263 tmp = def->nameClass;
5264 while (tmp->next != NULL) {
5265 tmp = tmp->next;
5266 }
5267 tmp->next = ret;
5268 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005269 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005270 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005271}
5272
5273/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005274 * xmlRelaxNGParseElement:
5275 * @ctxt: a Relax-NG parser context
5276 * @node: the element node
5277 *
5278 * parse the content of a RelaxNG element node.
5279 *
5280 * Returns the definition pointer or NULL in case of error.
5281 */
5282static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005283xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5284{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005285 xmlRelaxNGDefinePtr ret, cur, last;
5286 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005287 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005288
Daniel Veillardfd573f12003-03-16 17:52:32 +00005289 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005290 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005291 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005292 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005293 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005294 child = node->children;
5295 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005296 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5297 "xmlRelaxNGParseElement: element has no children\n",
5298 NULL, NULL);
5299 return (ret);
5300 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005301 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5302 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005303 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005304
Daniel Veillard6eadf632003-01-23 18:29:16 +00005305 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005306 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5307 "xmlRelaxNGParseElement: element has no content\n",
5308 NULL, NULL);
5309 return (ret);
5310 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005311 olddefine = ctxt->define;
5312 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005313 last = NULL;
5314 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005315 cur = xmlRelaxNGParsePattern(ctxt, child);
5316 if (cur != NULL) {
5317 cur->parent = ret;
5318 switch (cur->type) {
5319 case XML_RELAXNG_EMPTY:
5320 case XML_RELAXNG_NOT_ALLOWED:
5321 case XML_RELAXNG_TEXT:
5322 case XML_RELAXNG_ELEMENT:
5323 case XML_RELAXNG_DATATYPE:
5324 case XML_RELAXNG_VALUE:
5325 case XML_RELAXNG_LIST:
5326 case XML_RELAXNG_REF:
5327 case XML_RELAXNG_PARENTREF:
5328 case XML_RELAXNG_EXTERNALREF:
5329 case XML_RELAXNG_DEF:
5330 case XML_RELAXNG_ZEROORMORE:
5331 case XML_RELAXNG_ONEORMORE:
5332 case XML_RELAXNG_OPTIONAL:
5333 case XML_RELAXNG_CHOICE:
5334 case XML_RELAXNG_GROUP:
5335 case XML_RELAXNG_INTERLEAVE:
5336 if (last == NULL) {
5337 ret->content = last = cur;
5338 } else {
5339 if ((last->type == XML_RELAXNG_ELEMENT) &&
5340 (ret->content == last)) {
5341 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5342 if (ret->content != NULL) {
5343 ret->content->type = XML_RELAXNG_GROUP;
5344 ret->content->content = last;
5345 } else {
5346 ret->content = last;
5347 }
5348 }
5349 last->next = cur;
5350 last = cur;
5351 }
5352 break;
5353 case XML_RELAXNG_ATTRIBUTE:
5354 cur->next = ret->attrs;
5355 ret->attrs = cur;
5356 break;
5357 case XML_RELAXNG_START:
5358 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5359 "RNG Internal error, start found in element\n",
5360 NULL, NULL);
5361 break;
5362 case XML_RELAXNG_PARAM:
5363 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5364 "RNG Internal error, param found in element\n",
5365 NULL, NULL);
5366 break;
5367 case XML_RELAXNG_EXCEPT:
5368 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5369 "RNG Internal error, except found in element\n",
5370 NULL, NULL);
5371 break;
5372 case XML_RELAXNG_NOOP:
5373 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5374 "RNG Internal error, noop found in element\n",
5375 NULL, NULL);
5376 break;
5377 }
5378 }
5379 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005380 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005381 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005382 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005383}
5384
5385/**
5386 * xmlRelaxNGParsePatterns:
5387 * @ctxt: a Relax-NG parser context
5388 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005389 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005390 *
5391 * parse the content of a RelaxNG start node.
5392 *
5393 * Returns the definition pointer or NULL in case of error.
5394 */
5395static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005396xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005397 int group)
5398{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005399 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005400
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005401 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005402 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005403 if (IS_RELAXNG(nodes, "element")) {
5404 cur = xmlRelaxNGParseElement(ctxt, nodes);
5405 if (def == NULL) {
5406 def = last = cur;
5407 } else {
5408 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5409 (def == last)) {
5410 def = xmlRelaxNGNewDefine(ctxt, nodes);
5411 def->type = XML_RELAXNG_GROUP;
5412 def->content = last;
5413 }
5414 last->next = cur;
5415 last = cur;
5416 }
5417 cur->parent = parent;
5418 } else {
5419 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5420 if (cur != NULL) {
5421 if (def == NULL) {
5422 def = last = cur;
5423 } else {
5424 last->next = cur;
5425 last = cur;
5426 }
5427 }
5428 }
5429 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005430 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005431 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005432}
5433
5434/**
5435 * xmlRelaxNGParseStart:
5436 * @ctxt: a Relax-NG parser context
5437 * @nodes: start children nodes
5438 *
5439 * parse the content of a RelaxNG start node.
5440 *
5441 * Returns 0 in case of success, -1 in case of error
5442 */
5443static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005444xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5445{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005446 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005447 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005448
Daniel Veillardd2298792003-02-14 16:54:11 +00005449 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005450 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5451 NULL, NULL);
5452 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005453 }
5454 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005455 def = xmlRelaxNGNewDefine(ctxt, nodes);
5456 if (def == NULL)
5457 return (-1);
5458 def->type = XML_RELAXNG_EMPTY;
5459 if (nodes->children != NULL) {
5460 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5461 "element empty is not empty\n", NULL, NULL);
5462 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005463 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005464 def = xmlRelaxNGNewDefine(ctxt, nodes);
5465 if (def == NULL)
5466 return (-1);
5467 def->type = XML_RELAXNG_NOT_ALLOWED;
5468 if (nodes->children != NULL) {
5469 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5470 "element notAllowed is not empty\n", NULL, NULL);
5471 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005472 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005473 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005474 }
5475 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005476 last = ctxt->grammar->start;
5477 while (last->next != NULL)
5478 last = last->next;
5479 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005480 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005481 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005482 }
5483 nodes = nodes->next;
5484 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005485 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5486 "start more than one children\n", NULL, NULL);
5487 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005488 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005489 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005490}
5491
5492/**
5493 * xmlRelaxNGParseGrammarContent:
5494 * @ctxt: a Relax-NG parser context
5495 * @nodes: grammar children nodes
5496 *
5497 * parse the content of a RelaxNG grammar node.
5498 *
5499 * Returns 0 in case of success, -1 in case of error
5500 */
5501static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005502xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5503 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005504{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005505 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506
5507 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005508 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5509 "grammar has no children\n", NULL, NULL);
5510 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005511 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005512 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005513 if (IS_RELAXNG(nodes, "start")) {
5514 if (nodes->children == NULL) {
5515 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5516 "start has no children\n", NULL, NULL);
5517 } else {
5518 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5519 if (tmp != 0)
5520 ret = -1;
5521 }
5522 } else if (IS_RELAXNG(nodes, "define")) {
5523 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5524 if (tmp != 0)
5525 ret = -1;
5526 } else if (IS_RELAXNG(nodes, "include")) {
5527 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5528 if (tmp != 0)
5529 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005530 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005531 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5532 "grammar has unexpected child %s\n", nodes->name,
5533 NULL);
5534 ret = -1;
5535 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005536 nodes = nodes->next;
5537 }
5538 return (ret);
5539}
5540
5541/**
5542 * xmlRelaxNGCheckReference:
5543 * @ref: the ref
5544 * @ctxt: a Relax-NG parser context
5545 * @name: the name associated to the defines
5546 *
5547 * Applies the 4.17. combine attribute rule for all the define
5548 * element of a given grammar using the same name.
5549 */
5550static void
5551xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005552 xmlRelaxNGParserCtxtPtr ctxt,
5553 const xmlChar * name)
5554{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005555 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005556 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005557
5558 grammar = ctxt->grammar;
5559 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005560 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5561 "Internal error: no grammar in CheckReference %s\n",
5562 name, NULL);
5563 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005564 }
5565 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005566 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5567 "Internal error: reference has content in CheckReference %s\n",
5568 name, NULL);
5569 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005570 }
5571 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005572 def = xmlHashLookup(grammar->defs, name);
5573 if (def != NULL) {
5574 cur = ref;
5575 while (cur != NULL) {
5576 cur->content = def;
5577 cur = cur->nextHash;
5578 }
5579 } else {
5580 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5581 "Reference %s has no matching definition\n", name,
5582 NULL);
5583 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005584 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005585 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5586 "Reference %s has no matching definition\n", name,
5587 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005588 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005589}
5590
5591/**
5592 * xmlRelaxNGCheckCombine:
5593 * @define: the define(s) list
5594 * @ctxt: a Relax-NG parser context
5595 * @name: the name associated to the defines
5596 *
5597 * Applies the 4.17. combine attribute rule for all the define
5598 * element of a given grammar using the same name.
5599 */
5600static void
5601xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005602 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5603{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005604 xmlChar *combine;
5605 int choiceOrInterleave = -1;
5606 int missing = 0;
5607 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5608
5609 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005610 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005611 cur = define;
5612 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005613 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5614 if (combine != NULL) {
5615 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5616 if (choiceOrInterleave == -1)
5617 choiceOrInterleave = 1;
5618 else if (choiceOrInterleave == 0) {
5619 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5620 "Defines for %s use both 'choice' and 'interleave'\n",
5621 name, NULL);
5622 }
5623 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5624 if (choiceOrInterleave == -1)
5625 choiceOrInterleave = 0;
5626 else if (choiceOrInterleave == 1) {
5627 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5628 "Defines for %s use both 'choice' and 'interleave'\n",
5629 name, NULL);
5630 }
5631 } else {
5632 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5633 "Defines for %s use unknown combine value '%s''\n",
5634 name, combine);
5635 }
5636 xmlFree(combine);
5637 } else {
5638 if (missing == 0)
5639 missing = 1;
5640 else {
5641 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5642 "Some defines for %s needs the combine attribute\n",
5643 name, NULL);
5644 }
5645 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005646
Daniel Veillard4c004142003-10-07 11:33:24 +00005647 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005648 }
5649#ifdef DEBUG
5650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005651 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5652 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005653#endif
5654 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005655 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005656 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005657 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005658 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005659 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005660 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005661 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005662 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005663 tmp = define;
5664 last = NULL;
5665 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005666 if (tmp->content != NULL) {
5667 if (tmp->content->next != NULL) {
5668 /*
5669 * we need first to create a wrapper.
5670 */
5671 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5672 if (tmp2 == NULL)
5673 break;
5674 tmp2->type = XML_RELAXNG_GROUP;
5675 tmp2->content = tmp->content;
5676 } else {
5677 tmp2 = tmp->content;
5678 }
5679 if (last == NULL) {
5680 cur->content = tmp2;
5681 } else {
5682 last->next = tmp2;
5683 }
5684 last = tmp2;
5685 }
5686 tmp->content = cur;
5687 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005688 }
5689 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005690 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005691 if (ctxt->interleaves == NULL)
5692 ctxt->interleaves = xmlHashCreate(10);
5693 if (ctxt->interleaves == NULL) {
5694 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5695 "Failed to create interleaves hash table\n", NULL,
5696 NULL);
5697 } else {
5698 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005699
Daniel Veillard4c004142003-10-07 11:33:24 +00005700 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5701 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5702 0) {
5703 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5704 "Failed to add %s to hash table\n",
5705 (const xmlChar *) tmpname, NULL);
5706 }
5707 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005708 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005709}
5710
5711/**
5712 * xmlRelaxNGCombineStart:
5713 * @ctxt: a Relax-NG parser context
5714 * @grammar: the grammar
5715 *
5716 * Applies the 4.17. combine rule for all the start
5717 * element of a given grammar.
5718 */
5719static void
5720xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005721 xmlRelaxNGGrammarPtr grammar)
5722{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005723 xmlRelaxNGDefinePtr starts;
5724 xmlChar *combine;
5725 int choiceOrInterleave = -1;
5726 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005727 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005728
Daniel Veillard2df2de22003-02-17 23:34:33 +00005729 starts = grammar->start;
5730 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005731 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005732 cur = starts;
5733 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005734 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5735 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5736 combine = NULL;
5737 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5738 "Internal error: start element not found\n", NULL,
5739 NULL);
5740 } else {
5741 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5742 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005743
Daniel Veillard4c004142003-10-07 11:33:24 +00005744 if (combine != NULL) {
5745 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5746 if (choiceOrInterleave == -1)
5747 choiceOrInterleave = 1;
5748 else if (choiceOrInterleave == 0) {
5749 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5750 "<start> use both 'choice' and 'interleave'\n",
5751 NULL, NULL);
5752 }
5753 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5754 if (choiceOrInterleave == -1)
5755 choiceOrInterleave = 0;
5756 else if (choiceOrInterleave == 1) {
5757 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5758 "<start> use both 'choice' and 'interleave'\n",
5759 NULL, NULL);
5760 }
5761 } else {
5762 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5763 "<start> uses unknown combine value '%s''\n",
5764 combine, NULL);
5765 }
5766 xmlFree(combine);
5767 } else {
5768 if (missing == 0)
5769 missing = 1;
5770 else {
5771 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5772 "Some <start> element miss the combine attribute\n",
5773 NULL, NULL);
5774 }
5775 }
5776
5777 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005778 }
5779#ifdef DEBUG
5780 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005781 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5782 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005783#endif
5784 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005785 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005786 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005787 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005788 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005789 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005790 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005791 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005792 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005793 cur->content = grammar->start;
5794 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005795 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005796 if (ctxt->interleaves == NULL)
5797 ctxt->interleaves = xmlHashCreate(10);
5798 if (ctxt->interleaves == NULL) {
5799 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5800 "Failed to create interleaves hash table\n", NULL,
5801 NULL);
5802 } else {
5803 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005804
Daniel Veillard4c004142003-10-07 11:33:24 +00005805 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5806 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5807 0) {
5808 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5809 "Failed to add %s to hash table\n",
5810 (const xmlChar *) tmpname, NULL);
5811 }
5812 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005813 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005814}
5815
5816/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005817 * xmlRelaxNGCheckCycles:
5818 * @ctxt: a Relax-NG parser context
5819 * @nodes: grammar children nodes
5820 * @depth: the counter
5821 *
5822 * Check for cycles.
5823 *
5824 * Returns 0 if check passed, and -1 in case of error
5825 */
5826static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005827xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5828 xmlRelaxNGDefinePtr cur, int depth)
5829{
Daniel Veillardd4310742003-02-18 21:12:46 +00005830 int ret = 0;
5831
5832 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005833 if ((cur->type == XML_RELAXNG_REF) ||
5834 (cur->type == XML_RELAXNG_PARENTREF)) {
5835 if (cur->depth == -1) {
5836 cur->depth = depth;
5837 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5838 cur->depth = -2;
5839 } else if (depth == cur->depth) {
5840 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5841 "Detected a cycle in %s references\n",
5842 cur->name, NULL);
5843 return (-1);
5844 }
5845 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5846 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5847 } else {
5848 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5849 }
5850 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005851 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005852 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005853}
5854
5855/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005856 * xmlRelaxNGTryUnlink:
5857 * @ctxt: a Relax-NG parser context
5858 * @cur: the definition to unlink
5859 * @parent: the parent definition
5860 * @prev: the previous sibling definition
5861 *
5862 * Try to unlink a definition. If not possble make it a NOOP
5863 *
5864 * Returns the new prev definition
5865 */
5866static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005867xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5868 xmlRelaxNGDefinePtr cur,
5869 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5870{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005871 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005872 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005873 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005874 if (parent != NULL) {
5875 if (parent->content == cur)
5876 parent->content = cur->next;
5877 else if (parent->attrs == cur)
5878 parent->attrs = cur->next;
5879 else if (parent->nameClass == cur)
5880 parent->nameClass = cur->next;
5881 } else {
5882 cur->type = XML_RELAXNG_NOOP;
5883 prev = cur;
5884 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005885 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005886 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005887}
5888
5889/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005890 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005891 * @ctxt: a Relax-NG parser context
5892 * @nodes: grammar children nodes
5893 *
5894 * Check for simplification of empty and notAllowed
5895 */
5896static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005897xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5898 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5899{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005900 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005901
Daniel Veillardfd573f12003-03-16 17:52:32 +00005902 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005903 if ((cur->type == XML_RELAXNG_REF) ||
5904 (cur->type == XML_RELAXNG_PARENTREF)) {
5905 if (cur->depth != -3) {
5906 cur->depth = -3;
5907 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5908 }
5909 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5910 cur->parent = parent;
5911 if ((parent != NULL) &&
5912 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5913 (parent->type == XML_RELAXNG_LIST) ||
5914 (parent->type == XML_RELAXNG_GROUP) ||
5915 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5916 (parent->type == XML_RELAXNG_ONEORMORE) ||
5917 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5918 parent->type = XML_RELAXNG_NOT_ALLOWED;
5919 break;
5920 }
5921 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5922 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5923 } else
5924 prev = cur;
5925 } else if (cur->type == XML_RELAXNG_EMPTY) {
5926 cur->parent = parent;
5927 if ((parent != NULL) &&
5928 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5929 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5930 parent->type = XML_RELAXNG_EMPTY;
5931 break;
5932 }
5933 if ((parent != NULL) &&
5934 ((parent->type == XML_RELAXNG_GROUP) ||
5935 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5936 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5937 } else
5938 prev = cur;
5939 } else {
5940 cur->parent = parent;
5941 if (cur->content != NULL)
5942 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5943 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5944 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5945 if (cur->nameClass != NULL)
5946 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5947 /*
5948 * On Elements, try to move attribute only generating rules on
5949 * the attrs rules.
5950 */
5951 if (cur->type == XML_RELAXNG_ELEMENT) {
5952 int attronly;
5953 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005954
Daniel Veillard4c004142003-10-07 11:33:24 +00005955 while (cur->content != NULL) {
5956 attronly =
5957 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5958 if (attronly == 1) {
5959 /*
5960 * migrate cur->content to attrs
5961 */
5962 tmp = cur->content;
5963 cur->content = tmp->next;
5964 tmp->next = cur->attrs;
5965 cur->attrs = tmp;
5966 } else {
5967 /*
5968 * cur->content can generate elements or text
5969 */
5970 break;
5971 }
5972 }
5973 pre = cur->content;
5974 while ((pre != NULL) && (pre->next != NULL)) {
5975 tmp = pre->next;
5976 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5977 if (attronly == 1) {
5978 /*
5979 * migrate tmp to attrs
5980 */
5981 pre->next = tmp->next;
5982 tmp->next = cur->attrs;
5983 cur->attrs = tmp;
5984 } else {
5985 pre = tmp;
5986 }
5987 }
5988 }
5989 /*
5990 * This may result in a simplification
5991 */
5992 if ((cur->type == XML_RELAXNG_GROUP) ||
5993 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5994 if (cur->content == NULL)
5995 cur->type = XML_RELAXNG_EMPTY;
5996 else if (cur->content->next == NULL) {
5997 if ((parent == NULL) && (prev == NULL)) {
5998 cur->type = XML_RELAXNG_NOOP;
5999 } else if (prev == NULL) {
6000 parent->content = cur->content;
6001 cur->content->next = cur->next;
6002 cur = cur->content;
6003 } else {
6004 cur->content->next = cur->next;
6005 prev->next = cur->content;
6006 cur = cur->content;
6007 }
6008 }
6009 }
6010 /*
6011 * the current node may have been transformed back
6012 */
6013 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6014 (cur->content != NULL) &&
6015 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6016 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6017 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6018 if ((parent != NULL) &&
6019 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6020 (parent->type == XML_RELAXNG_LIST) ||
6021 (parent->type == XML_RELAXNG_GROUP) ||
6022 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6023 (parent->type == XML_RELAXNG_ONEORMORE) ||
6024 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6025 parent->type = XML_RELAXNG_NOT_ALLOWED;
6026 break;
6027 }
6028 if ((parent != NULL) &&
6029 (parent->type == XML_RELAXNG_CHOICE)) {
6030 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6031 } else
6032 prev = cur;
6033 } else if (cur->type == XML_RELAXNG_EMPTY) {
6034 if ((parent != NULL) &&
6035 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6036 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6037 parent->type = XML_RELAXNG_EMPTY;
6038 break;
6039 }
6040 if ((parent != NULL) &&
6041 ((parent->type == XML_RELAXNG_GROUP) ||
6042 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6043 (parent->type == XML_RELAXNG_CHOICE))) {
6044 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6045 } else
6046 prev = cur;
6047 } else {
6048 prev = cur;
6049 }
6050 }
6051 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006052 }
6053}
6054
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006055/**
6056 * xmlRelaxNGGroupContentType:
6057 * @ct1: the first content type
6058 * @ct2: the second content type
6059 *
6060 * Try to group 2 content types
6061 *
6062 * Returns the content type
6063 */
6064static xmlRelaxNGContentType
6065xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006066 xmlRelaxNGContentType ct2)
6067{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006068 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006069 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6070 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006071 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006072 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006073 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006074 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006075 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006076 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6077 return (XML_RELAXNG_CONTENT_COMPLEX);
6078 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006079}
6080
6081/**
6082 * xmlRelaxNGMaxContentType:
6083 * @ct1: the first content type
6084 * @ct2: the second content type
6085 *
6086 * Compute the max content-type
6087 *
6088 * Returns the content type
6089 */
6090static xmlRelaxNGContentType
6091xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006092 xmlRelaxNGContentType ct2)
6093{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006094 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006095 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6096 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006097 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006098 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6099 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006100 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006101 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6102 return (XML_RELAXNG_CONTENT_COMPLEX);
6103 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006104}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006105
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006106/**
6107 * xmlRelaxNGCheckRules:
6108 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006109 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006110 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006111 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006112 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006113 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006114 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006115 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006116 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006117static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006118xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6119 xmlRelaxNGDefinePtr cur, int flags,
6120 xmlRelaxNGType ptype)
6121{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006122 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006123 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006124
Daniel Veillardfd573f12003-03-16 17:52:32 +00006125 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006126 ret = XML_RELAXNG_CONTENT_EMPTY;
6127 if ((cur->type == XML_RELAXNG_REF) ||
6128 (cur->type == XML_RELAXNG_PARENTREF)) {
Daniel Veillard63d68a32005-03-31 13:50:00 +00006129 /*
6130 * This should actually be caught by list//element(ref) at the
6131 * element boundaries, c.f. Bug #159968 local refs are dropped
6132 * in step 4.19.
6133 */
6134#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00006135 if (flags & XML_RELAXNG_IN_LIST) {
6136 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6137 "Found forbidden pattern list//ref\n", NULL,
6138 NULL);
6139 }
Daniel Veillard63d68a32005-03-31 13:50:00 +00006140#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00006141 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6142 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6143 "Found forbidden pattern data/except//ref\n",
6144 NULL, NULL);
6145 }
6146 if (cur->depth > -4) {
6147 cur->depth = -4;
6148 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6149 flags, cur->type);
6150 cur->depth = ret - 15;
6151 } else if (cur->depth == -4) {
6152 ret = XML_RELAXNG_CONTENT_COMPLEX;
6153 } else {
6154 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6155 }
6156 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6157 /*
6158 * The 7.3 Attribute derivation rule for groups is plugged there
6159 */
6160 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6161 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6162 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6163 "Found forbidden pattern data/except//element(ref)\n",
6164 NULL, NULL);
6165 }
6166 if (flags & XML_RELAXNG_IN_LIST) {
6167 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6168 "Found forbidden pattern list//element(ref)\n",
6169 NULL, NULL);
6170 }
6171 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6172 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6173 "Found forbidden pattern attribute//element(ref)\n",
6174 NULL, NULL);
6175 }
6176 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6177 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6178 "Found forbidden pattern attribute//element(ref)\n",
6179 NULL, NULL);
6180 }
6181 /*
6182 * reset since in the simple form elements are only child
6183 * of grammar/define
6184 */
6185 nflags = 0;
6186 ret =
6187 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6188 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6189 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6190 "Element %s attributes have a content type error\n",
6191 cur->name, NULL);
6192 }
6193 ret =
6194 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6195 cur->type);
6196 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6197 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6198 "Element %s has a content type error\n",
6199 cur->name, NULL);
6200 } else {
6201 ret = XML_RELAXNG_CONTENT_COMPLEX;
6202 }
6203 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6204 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6205 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6206 "Found forbidden pattern attribute//attribute\n",
6207 NULL, NULL);
6208 }
6209 if (flags & XML_RELAXNG_IN_LIST) {
6210 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6211 "Found forbidden pattern list//attribute\n",
6212 NULL, NULL);
6213 }
6214 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6215 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6216 "Found forbidden pattern oneOrMore//group//attribute\n",
6217 NULL, NULL);
6218 }
6219 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6220 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6221 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6222 NULL, NULL);
6223 }
6224 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6225 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6226 "Found forbidden pattern data/except//attribute\n",
6227 NULL, NULL);
6228 }
6229 if (flags & XML_RELAXNG_IN_START) {
6230 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6231 "Found forbidden pattern start//attribute\n",
6232 NULL, NULL);
6233 }
6234 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6235 && (cur->name == NULL)) {
6236 if (cur->ns == NULL) {
6237 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6238 "Found anyName attribute without oneOrMore ancestor\n",
6239 NULL, NULL);
6240 } else {
6241 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6242 "Found nsName attribute without oneOrMore ancestor\n",
6243 NULL, NULL);
6244 }
6245 }
6246 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6247 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6248 ret = XML_RELAXNG_CONTENT_EMPTY;
6249 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6250 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6251 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6252 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6253 "Found forbidden pattern data/except//oneOrMore\n",
6254 NULL, NULL);
6255 }
6256 if (flags & XML_RELAXNG_IN_START) {
6257 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6258 "Found forbidden pattern start//oneOrMore\n",
6259 NULL, NULL);
6260 }
6261 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6262 ret =
6263 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6264 cur->type);
6265 ret = xmlRelaxNGGroupContentType(ret, ret);
6266 } else if (cur->type == XML_RELAXNG_LIST) {
6267 if (flags & XML_RELAXNG_IN_LIST) {
6268 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6269 "Found forbidden pattern list//list\n", NULL,
6270 NULL);
6271 }
6272 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6273 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6274 "Found forbidden pattern data/except//list\n",
6275 NULL, NULL);
6276 }
6277 if (flags & XML_RELAXNG_IN_START) {
6278 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6279 "Found forbidden pattern start//list\n", NULL,
6280 NULL);
6281 }
6282 nflags = flags | XML_RELAXNG_IN_LIST;
6283 ret =
6284 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6285 cur->type);
6286 } else if (cur->type == XML_RELAXNG_GROUP) {
6287 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6288 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6289 "Found forbidden pattern data/except//group\n",
6290 NULL, NULL);
6291 }
6292 if (flags & XML_RELAXNG_IN_START) {
6293 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6294 "Found forbidden pattern start//group\n", NULL,
6295 NULL);
6296 }
6297 if (flags & XML_RELAXNG_IN_ONEORMORE)
6298 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6299 else
6300 nflags = flags;
6301 ret =
6302 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6303 cur->type);
6304 /*
6305 * The 7.3 Attribute derivation rule for groups is plugged there
6306 */
6307 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6308 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6309 if (flags & XML_RELAXNG_IN_LIST) {
6310 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6311 "Found forbidden pattern list//interleave\n",
6312 NULL, NULL);
6313 }
6314 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6315 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6316 "Found forbidden pattern data/except//interleave\n",
6317 NULL, NULL);
6318 }
6319 if (flags & XML_RELAXNG_IN_START) {
6320 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6321 "Found forbidden pattern start//interleave\n",
6322 NULL, NULL);
6323 }
6324 if (flags & XML_RELAXNG_IN_ONEORMORE)
6325 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6326 else
6327 nflags = flags;
6328 ret =
6329 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6330 cur->type);
6331 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6332 if ((cur->parent != NULL) &&
6333 (cur->parent->type == XML_RELAXNG_DATATYPE))
6334 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6335 else
6336 nflags = flags;
6337 ret =
6338 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6339 cur->type);
6340 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6341 if (flags & XML_RELAXNG_IN_START) {
6342 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6343 "Found forbidden pattern start//data\n", NULL,
6344 NULL);
6345 }
6346 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6347 ret = XML_RELAXNG_CONTENT_SIMPLE;
6348 } else if (cur->type == XML_RELAXNG_VALUE) {
6349 if (flags & XML_RELAXNG_IN_START) {
6350 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6351 "Found forbidden pattern start//value\n", NULL,
6352 NULL);
6353 }
6354 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6355 ret = XML_RELAXNG_CONTENT_SIMPLE;
6356 } else if (cur->type == XML_RELAXNG_TEXT) {
6357 if (flags & XML_RELAXNG_IN_LIST) {
6358 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6359 "Found forbidden pattern list//text\n", NULL,
6360 NULL);
6361 }
6362 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6363 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6364 "Found forbidden pattern data/except//text\n",
6365 NULL, NULL);
6366 }
6367 if (flags & XML_RELAXNG_IN_START) {
6368 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6369 "Found forbidden pattern start//text\n", NULL,
6370 NULL);
6371 }
6372 ret = XML_RELAXNG_CONTENT_COMPLEX;
6373 } else if (cur->type == XML_RELAXNG_EMPTY) {
6374 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6375 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6376 "Found forbidden pattern data/except//empty\n",
6377 NULL, NULL);
6378 }
6379 if (flags & XML_RELAXNG_IN_START) {
6380 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6381 "Found forbidden pattern start//empty\n", NULL,
6382 NULL);
6383 }
6384 ret = XML_RELAXNG_CONTENT_EMPTY;
6385 } else if (cur->type == XML_RELAXNG_CHOICE) {
6386 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6387 ret =
6388 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6389 } else {
6390 ret =
6391 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6392 }
6393 cur = cur->next;
6394 if (ptype == XML_RELAXNG_GROUP) {
6395 val = xmlRelaxNGGroupContentType(val, ret);
6396 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6397 tmp = xmlRelaxNGGroupContentType(val, ret);
6398 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6399 tmp = xmlRelaxNGMaxContentType(val, ret);
6400 } else if (ptype == XML_RELAXNG_CHOICE) {
6401 val = xmlRelaxNGMaxContentType(val, ret);
6402 } else if (ptype == XML_RELAXNG_LIST) {
6403 val = XML_RELAXNG_CONTENT_SIMPLE;
6404 } else if (ptype == XML_RELAXNG_EXCEPT) {
6405 if (ret == XML_RELAXNG_CONTENT_ERROR)
6406 val = XML_RELAXNG_CONTENT_ERROR;
6407 else
6408 val = XML_RELAXNG_CONTENT_SIMPLE;
6409 } else {
6410 val = xmlRelaxNGGroupContentType(val, ret);
6411 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006412
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006413 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006414 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006415}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006416
6417/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006418 * xmlRelaxNGParseGrammar:
6419 * @ctxt: a Relax-NG parser context
6420 * @nodes: grammar children nodes
6421 *
6422 * parse a Relax-NG <grammar> node
6423 *
6424 * Returns the internal xmlRelaxNGGrammarPtr built or
6425 * NULL in case of error
6426 */
6427static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006428xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6429{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006430 xmlRelaxNGGrammarPtr ret, tmp, old;
6431
Daniel Veillardc482e262003-02-26 14:48:48 +00006432#ifdef DEBUG_GRAMMAR
6433 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6434#endif
6435
Daniel Veillard6eadf632003-01-23 18:29:16 +00006436 ret = xmlRelaxNGNewGrammar(ctxt);
6437 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006438 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006439
6440 /*
6441 * Link the new grammar in the tree
6442 */
6443 ret->parent = ctxt->grammar;
6444 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006445 tmp = ctxt->grammar->children;
6446 if (tmp == NULL) {
6447 ctxt->grammar->children = ret;
6448 } else {
6449 while (tmp->next != NULL)
6450 tmp = tmp->next;
6451 tmp->next = ret;
6452 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006453 }
6454
6455 old = ctxt->grammar;
6456 ctxt->grammar = ret;
6457 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6458 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006459 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006460 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6461 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006462 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006463 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6464 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006465 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006466
6467 /*
6468 * Apply 4.17 mergingd rules to defines and starts
6469 */
6470 xmlRelaxNGCombineStart(ctxt, ret);
6471 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006472 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6473 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006474 }
6475
6476 /*
6477 * link together defines and refs in this grammar
6478 */
6479 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006480 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6481 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006482 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006483
Daniel Veillard6eadf632003-01-23 18:29:16 +00006484 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006485 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006486}
6487
6488/**
6489 * xmlRelaxNGParseDocument:
6490 * @ctxt: a Relax-NG parser context
6491 * @node: the root node of the RelaxNG schema
6492 *
6493 * parse a Relax-NG definition resource and build an internal
6494 * xmlRelaxNG struture which can be used to validate instances.
6495 *
6496 * Returns the internal XML RelaxNG structure built or
6497 * NULL in case of error
6498 */
6499static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006500xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6501{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006502 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006503 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006504 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006505
6506 if ((ctxt == NULL) || (node == NULL))
6507 return (NULL);
6508
6509 schema = xmlRelaxNGNewRelaxNG(ctxt);
6510 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006511 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006512
Daniel Veillard276be4a2003-01-24 01:03:34 +00006513 olddefine = ctxt->define;
6514 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006515 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006516 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006517 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006518 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006519
Daniel Veillard4c004142003-10-07 11:33:24 +00006520 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6521 if (schema->topgrammar == NULL) {
6522 return (schema);
6523 }
6524 /*
6525 * Link the new grammar in the tree
6526 */
6527 ret->parent = ctxt->grammar;
6528 if (ctxt->grammar != NULL) {
6529 tmp = ctxt->grammar->children;
6530 if (tmp == NULL) {
6531 ctxt->grammar->children = ret;
6532 } else {
6533 while (tmp->next != NULL)
6534 tmp = tmp->next;
6535 tmp->next = ret;
6536 }
6537 }
6538 old = ctxt->grammar;
6539 ctxt->grammar = ret;
6540 xmlRelaxNGParseStart(ctxt, node);
6541 if (old != NULL)
6542 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006543 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006544 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006545 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006546 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6547 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6548 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6549 while ((schema->topgrammar->start != NULL) &&
6550 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6551 (schema->topgrammar->start->next != NULL))
6552 schema->topgrammar->start =
6553 schema->topgrammar->start->content;
6554 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6555 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6556 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006557 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006558#ifdef DEBUG
6559 if (schema == NULL)
6560 xmlGenericError(xmlGenericErrorContext,
6561 "xmlRelaxNGParseDocument() failed\n");
6562#endif
6563
6564 return (schema);
6565}
6566
6567/************************************************************************
6568 * *
6569 * Reading RelaxNGs *
6570 * *
6571 ************************************************************************/
6572
6573/**
6574 * xmlRelaxNGNewParserCtxt:
6575 * @URL: the location of the schema
6576 *
6577 * Create an XML RelaxNGs parse context for that file/resource expected
6578 * to contain an XML RelaxNGs file.
6579 *
6580 * Returns the parser context or NULL in case of error
6581 */
6582xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006583xmlRelaxNGNewParserCtxt(const char *URL)
6584{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006585 xmlRelaxNGParserCtxtPtr ret;
6586
6587 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006588 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006589
Daniel Veillard4c004142003-10-07 11:33:24 +00006590 ret =
6591 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006592 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006593 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006594 return (NULL);
6595 }
6596 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006597 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006598 ret->error = xmlGenericError;
6599 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006600 return (ret);
6601}
6602
6603/**
6604 * xmlRelaxNGNewMemParserCtxt:
6605 * @buffer: a pointer to a char array containing the schemas
6606 * @size: the size of the array
6607 *
6608 * Create an XML RelaxNGs parse context for that memory buffer expected
6609 * to contain an XML RelaxNGs file.
6610 *
6611 * Returns the parser context or NULL in case of error
6612 */
6613xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006614xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6615{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006616 xmlRelaxNGParserCtxtPtr ret;
6617
6618 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006619 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006620
Daniel Veillard4c004142003-10-07 11:33:24 +00006621 ret =
6622 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006623 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006624 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006625 return (NULL);
6626 }
6627 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6628 ret->buffer = buffer;
6629 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006630 ret->error = xmlGenericError;
6631 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006632 return (ret);
6633}
6634
6635/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006636 * xmlRelaxNGNewDocParserCtxt:
6637 * @doc: a preparsed document tree
6638 *
6639 * Create an XML RelaxNGs parser context for that document.
6640 * Note: since the process of compiling a RelaxNG schemas modifies the
6641 * document, the @doc parameter is duplicated internally.
6642 *
6643 * Returns the parser context or NULL in case of error
6644 */
6645xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006646xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6647{
Daniel Veillard33300b42003-04-17 09:09:19 +00006648 xmlRelaxNGParserCtxtPtr ret;
6649 xmlDocPtr copy;
6650
6651 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006652 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006653 copy = xmlCopyDoc(doc, 1);
6654 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006655 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006656
Daniel Veillard4c004142003-10-07 11:33:24 +00006657 ret =
6658 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006659 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006660 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006661 return (NULL);
6662 }
6663 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6664 ret->document = copy;
Daniel Veillard42595322004-11-08 10:52:06 +00006665 ret->freedoc = 1;
Daniel Veillard33300b42003-04-17 09:09:19 +00006666 ret->userData = xmlGenericErrorContext;
6667 return (ret);
6668}
6669
6670/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006671 * xmlRelaxNGFreeParserCtxt:
6672 * @ctxt: the schema parser context
6673 *
6674 * Free the resources associated to the schema parser context
6675 */
6676void
Daniel Veillard4c004142003-10-07 11:33:24 +00006677xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6678{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006679 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006680 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006681 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006682 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006683 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006684 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006685 if (ctxt->interleaves != NULL)
6686 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006687 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006688 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006689 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006690 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006691 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006692 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006693 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006694 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006695 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006696 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006697
Daniel Veillard4c004142003-10-07 11:33:24 +00006698 for (i = 0; i < ctxt->defNr; i++)
6699 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6700 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006701 }
Daniel Veillard42595322004-11-08 10:52:06 +00006702 if ((ctxt->document != NULL) && (ctxt->freedoc))
6703 xmlFreeDoc(ctxt->document);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006704 xmlFree(ctxt);
6705}
6706
Daniel Veillard6eadf632003-01-23 18:29:16 +00006707/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006708 * xmlRelaxNGNormExtSpace:
6709 * @value: a value
6710 *
6711 * Removes the leading and ending spaces of the value
6712 * The string is modified "in situ"
6713 */
6714static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006715xmlRelaxNGNormExtSpace(xmlChar * value)
6716{
Daniel Veillardd2298792003-02-14 16:54:11 +00006717 xmlChar *start = value;
6718 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006719
Daniel Veillard4c004142003-10-07 11:33:24 +00006720 if (value == NULL)
6721 return;
6722
William M. Brack76e95df2003-10-18 16:20:14 +00006723 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006724 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006725 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006726 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006727 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006728 cur++;
6729 if (*cur == 0)
6730 return;
6731 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006732 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006733 cur++;
6734 if (*cur == 0) {
6735 *start = 0;
6736 return;
6737 }
6738 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006739 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006740 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006741 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006742 *start++ = *cur++;
6743 if (*cur == 0) {
6744 *start = 0;
6745 return;
6746 }
6747 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006748 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006749 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006750 if (*cur == 0) {
6751 *start = 0;
6752 return;
6753 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006754 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006755 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006756 }
6757}
6758
6759/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006760 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006761 * @ctxt: a Relax-NG parser context
6762 * @node: a Relax-NG node
6763 *
6764 * Check all the attributes on the given node
6765 */
6766static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006767xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6768{
Daniel Veillardd2298792003-02-14 16:54:11 +00006769 xmlAttrPtr cur, next;
6770
6771 cur = node->properties;
6772 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006773 next = cur->next;
6774 if ((cur->ns == NULL) ||
6775 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6776 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6777 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6778 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6779 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6780 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6781 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6782 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6783 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6784 "Attribute %s is not allowed on %s\n",
6785 cur->name, node->name);
6786 }
6787 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6788 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6789 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6790 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6791 "Attribute %s is not allowed on %s\n",
6792 cur->name, node->name);
6793 }
6794 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6795 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6796 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6797 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6798 "Attribute %s is not allowed on %s\n",
6799 cur->name, node->name);
6800 }
6801 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6802 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6803 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6804 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6805 "Attribute %s is not allowed on %s\n",
6806 cur->name, node->name);
6807 }
6808 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6809 xmlChar *val;
6810 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006811
Daniel Veillard4c004142003-10-07 11:33:24 +00006812 val = xmlNodeListGetString(node->doc, cur->children, 1);
6813 if (val != NULL) {
6814 if (val[0] != 0) {
6815 uri = xmlParseURI((const char *) val);
6816 if (uri == NULL) {
6817 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6818 "Attribute %s contains invalid URI %s\n",
6819 cur->name, val);
6820 } else {
6821 if (uri->scheme == NULL) {
6822 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6823 "Attribute %s URI %s is not absolute\n",
6824 cur->name, val);
6825 }
6826 if (uri->fragment != NULL) {
6827 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6828 "Attribute %s URI %s has a fragment ID\n",
6829 cur->name, val);
6830 }
6831 xmlFreeURI(uri);
6832 }
6833 }
6834 xmlFree(val);
6835 }
6836 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6837 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6838 "Unknown attribute %s on %s\n", cur->name,
6839 node->name);
6840 }
6841 }
6842 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006843 }
6844}
6845
6846/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006847 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006848 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006849 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006850 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006851 * Cleanup the subtree from unwanted nodes for parsing, resolve
6852 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006853 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006854static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006855xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6856{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006857 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006858
Daniel Veillard6eadf632003-01-23 18:29:16 +00006859 delete = NULL;
6860 cur = root;
6861 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006862 if (delete != NULL) {
6863 xmlUnlinkNode(delete);
6864 xmlFreeNode(delete);
6865 delete = NULL;
6866 }
6867 if (cur->type == XML_ELEMENT_NODE) {
6868 /*
6869 * Simplification 4.1. Annotations
6870 */
6871 if ((cur->ns == NULL) ||
6872 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6873 if ((cur->parent != NULL) &&
6874 (cur->parent->type == XML_ELEMENT_NODE) &&
6875 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6876 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6877 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6878 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6879 "element %s doesn't allow foreign elements\n",
6880 cur->parent->name, NULL);
6881 }
6882 delete = cur;
6883 goto skip_children;
6884 } else {
6885 xmlRelaxNGCleanupAttributes(ctxt, cur);
6886 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6887 xmlChar *href, *ns, *base, *URL;
6888 xmlRelaxNGDocumentPtr docu;
6889 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006890 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006891
Daniel Veillard4c004142003-10-07 11:33:24 +00006892 ns = xmlGetProp(cur, BAD_CAST "ns");
6893 if (ns == NULL) {
6894 tmp = cur->parent;
6895 while ((tmp != NULL) &&
6896 (tmp->type == XML_ELEMENT_NODE)) {
6897 ns = xmlGetProp(tmp, BAD_CAST "ns");
6898 if (ns != NULL)
6899 break;
6900 tmp = tmp->parent;
6901 }
6902 }
6903 href = xmlGetProp(cur, BAD_CAST "href");
6904 if (href == NULL) {
6905 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6906 "xmlRelaxNGParse: externalRef has no href attribute\n",
6907 NULL, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006908 if (ns != NULL)
6909 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006910 delete = cur;
6911 goto skip_children;
6912 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006913 uri = xmlParseURI((const char *) href);
6914 if (uri == NULL) {
6915 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6916 "Incorrect URI for externalRef %s\n",
6917 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006918 if (ns != NULL)
6919 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00006920 if (href != NULL)
6921 xmlFree(href);
6922 delete = cur;
6923 goto skip_children;
6924 }
6925 if (uri->fragment != NULL) {
6926 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6927 "Fragment forbidden in URI for externalRef %s\n",
6928 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006929 if (ns != NULL)
6930 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00006931 xmlFreeURI(uri);
6932 if (href != NULL)
6933 xmlFree(href);
6934 delete = cur;
6935 goto skip_children;
6936 }
6937 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006938 base = xmlNodeGetBase(cur->doc, cur);
6939 URL = xmlBuildURI(href, base);
6940 if (URL == NULL) {
6941 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6942 "Failed to compute URL for externalRef %s\n",
6943 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006944 if (ns != NULL)
6945 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006946 if (href != NULL)
6947 xmlFree(href);
6948 if (base != NULL)
6949 xmlFree(base);
6950 delete = cur;
6951 goto skip_children;
6952 }
6953 if (href != NULL)
6954 xmlFree(href);
6955 if (base != NULL)
6956 xmlFree(base);
6957 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6958 if (docu == NULL) {
6959 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6960 "Failed to load externalRef %s\n", URL,
6961 NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006962 if (ns != NULL)
6963 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006964 xmlFree(URL);
6965 delete = cur;
6966 goto skip_children;
6967 }
6968 if (ns != NULL)
6969 xmlFree(ns);
6970 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006971 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006972 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6973 xmlChar *href, *ns, *base, *URL;
6974 xmlRelaxNGIncludePtr incl;
6975 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006976
Daniel Veillard4c004142003-10-07 11:33:24 +00006977 href = xmlGetProp(cur, BAD_CAST "href");
6978 if (href == NULL) {
6979 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6980 "xmlRelaxNGParse: include has no href attribute\n",
6981 NULL, NULL);
6982 delete = cur;
6983 goto skip_children;
6984 }
6985 base = xmlNodeGetBase(cur->doc, cur);
6986 URL = xmlBuildURI(href, base);
6987 if (URL == NULL) {
6988 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6989 "Failed to compute URL for include %s\n",
6990 href, NULL);
6991 if (href != NULL)
6992 xmlFree(href);
6993 if (base != NULL)
6994 xmlFree(base);
6995 delete = cur;
6996 goto skip_children;
6997 }
6998 if (href != NULL)
6999 xmlFree(href);
7000 if (base != NULL)
7001 xmlFree(base);
7002 ns = xmlGetProp(cur, BAD_CAST "ns");
7003 if (ns == NULL) {
7004 tmp = cur->parent;
7005 while ((tmp != NULL) &&
7006 (tmp->type == XML_ELEMENT_NODE)) {
7007 ns = xmlGetProp(tmp, BAD_CAST "ns");
7008 if (ns != NULL)
7009 break;
7010 tmp = tmp->parent;
7011 }
7012 }
7013 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7014 if (ns != NULL)
7015 xmlFree(ns);
7016 if (incl == NULL) {
7017 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7018 "Failed to load include %s\n", URL,
7019 NULL);
7020 xmlFree(URL);
7021 delete = cur;
7022 goto skip_children;
7023 }
7024 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007025 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007026 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7027 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7028 {
7029 xmlChar *name, *ns;
7030 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007031
Daniel Veillard4c004142003-10-07 11:33:24 +00007032 /*
7033 * Simplification 4.8. name attribute of element
7034 * and attribute elements
7035 */
7036 name = xmlGetProp(cur, BAD_CAST "name");
7037 if (name != NULL) {
7038 if (cur->children == NULL) {
7039 text =
7040 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7041 name);
7042 } else {
7043 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007044
Daniel Veillard03a53c32004-10-26 16:06:51 +00007045 node = xmlNewDocNode(cur->doc, cur->ns,
7046 BAD_CAST "name", NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00007047 if (node != NULL) {
7048 xmlAddPrevSibling(cur->children, node);
7049 text = xmlNewText(name);
7050 xmlAddChild(node, text);
7051 text = node;
7052 }
7053 }
7054 if (text == NULL) {
7055 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7056 "Failed to create a name %s element\n",
7057 name, NULL);
7058 }
7059 xmlUnsetProp(cur, BAD_CAST "name");
7060 xmlFree(name);
7061 ns = xmlGetProp(cur, BAD_CAST "ns");
7062 if (ns != NULL) {
7063 if (text != NULL) {
7064 xmlSetProp(text, BAD_CAST "ns", ns);
7065 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7066 }
7067 xmlFree(ns);
7068 } else if (xmlStrEqual(cur->name,
7069 BAD_CAST "attribute")) {
7070 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7071 }
7072 }
7073 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7074 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7075 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7076 /*
7077 * Simplification 4.8. name attribute of element
7078 * and attribute elements
7079 */
7080 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7081 xmlNodePtr node;
7082 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007083
Daniel Veillard4c004142003-10-07 11:33:24 +00007084 node = cur->parent;
7085 while ((node != NULL) &&
7086 (node->type == XML_ELEMENT_NODE)) {
7087 ns = xmlGetProp(node, BAD_CAST "ns");
7088 if (ns != NULL) {
7089 break;
7090 }
7091 node = node->parent;
7092 }
7093 if (ns == NULL) {
7094 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7095 } else {
7096 xmlSetProp(cur, BAD_CAST "ns", ns);
7097 xmlFree(ns);
7098 }
7099 }
7100 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7101 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007102
Daniel Veillard4c004142003-10-07 11:33:24 +00007103 /*
7104 * Simplification: 4.10. QNames
7105 */
7106 name = xmlNodeGetContent(cur);
7107 if (name != NULL) {
7108 local = xmlSplitQName2(name, &prefix);
7109 if (local != NULL) {
7110 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007111
Daniel Veillard4c004142003-10-07 11:33:24 +00007112 ns = xmlSearchNs(cur->doc, cur, prefix);
7113 if (ns == NULL) {
7114 xmlRngPErr(ctxt, cur,
7115 XML_RNGP_PREFIX_UNDEFINED,
7116 "xmlRelaxNGParse: no namespace for prefix %s\n",
7117 prefix, NULL);
7118 } else {
7119 xmlSetProp(cur, BAD_CAST "ns",
7120 ns->href);
7121 xmlNodeSetContent(cur, local);
7122 }
7123 xmlFree(local);
7124 xmlFree(prefix);
7125 }
7126 xmlFree(name);
7127 }
7128 }
7129 /*
7130 * 4.16
7131 */
7132 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7133 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7134 xmlRngPErr(ctxt, cur,
7135 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7136 "Found nsName/except//nsName forbidden construct\n",
7137 NULL, NULL);
7138 }
7139 }
7140 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7141 (cur != root)) {
7142 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007143
Daniel Veillard4c004142003-10-07 11:33:24 +00007144 /*
7145 * 4.16
7146 */
7147 if ((cur->parent != NULL) &&
7148 (xmlStrEqual
7149 (cur->parent->name, BAD_CAST "anyName"))) {
7150 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7151 xmlRelaxNGCleanupTree(ctxt, cur);
7152 ctxt->flags = oldflags;
7153 goto skip_children;
7154 } else if ((cur->parent != NULL) &&
7155 (xmlStrEqual
7156 (cur->parent->name, BAD_CAST "nsName"))) {
7157 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7158 xmlRelaxNGCleanupTree(ctxt, cur);
7159 ctxt->flags = oldflags;
7160 goto skip_children;
7161 }
7162 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7163 /*
7164 * 4.16
7165 */
7166 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7167 xmlRngPErr(ctxt, cur,
7168 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7169 "Found anyName/except//anyName forbidden construct\n",
7170 NULL, NULL);
7171 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7172 xmlRngPErr(ctxt, cur,
7173 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7174 "Found nsName/except//anyName forbidden construct\n",
7175 NULL, NULL);
7176 }
7177 }
7178 /*
7179 * Thisd is not an else since "include" is transformed
7180 * into a div
7181 */
7182 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7183 xmlChar *ns;
7184 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007185
Daniel Veillard4c004142003-10-07 11:33:24 +00007186 /*
7187 * implements rule 4.11
7188 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007189
Daniel Veillard4c004142003-10-07 11:33:24 +00007190 ns = xmlGetProp(cur, BAD_CAST "ns");
7191
7192 child = cur->children;
7193 ins = cur;
7194 while (child != NULL) {
7195 if (ns != NULL) {
7196 if (!xmlHasProp(child, BAD_CAST "ns")) {
7197 xmlSetProp(child, BAD_CAST "ns", ns);
7198 }
7199 }
7200 tmp = child->next;
7201 xmlUnlinkNode(child);
7202 ins = xmlAddNextSibling(ins, child);
7203 child = tmp;
7204 }
7205 if (ns != NULL)
7206 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007207 /*
7208 * Since we are about to delete cur, if it's nsDef is non-NULL we
7209 * need to preserve it (it contains the ns definitions for the
7210 * children we just moved). We'll just stick it on to the end
7211 * of cur->parent's list, since it's never going to be re-serialized
7212 * (bug 143738).
7213 */
7214 if (cur->nsDef != NULL) {
7215 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7216 while (parDef->next != NULL)
7217 parDef = parDef->next;
7218 parDef->next = cur->nsDef;
7219 cur->nsDef = NULL;
7220 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007221 delete = cur;
7222 goto skip_children;
7223 }
7224 }
7225 }
7226 /*
7227 * Simplification 4.2 whitespaces
7228 */
7229 else if ((cur->type == XML_TEXT_NODE) ||
7230 (cur->type == XML_CDATA_SECTION_NODE)) {
7231 if (IS_BLANK_NODE(cur)) {
7232 if (cur->parent->type == XML_ELEMENT_NODE) {
7233 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7234 &&
7235 (!xmlStrEqual
7236 (cur->parent->name, BAD_CAST "param")))
7237 delete = cur;
7238 } else {
7239 delete = cur;
7240 goto skip_children;
7241 }
7242 }
7243 } else {
7244 delete = cur;
7245 goto skip_children;
7246 }
7247
7248 /*
7249 * Skip to next node
7250 */
7251 if (cur->children != NULL) {
7252 if ((cur->children->type != XML_ENTITY_DECL) &&
7253 (cur->children->type != XML_ENTITY_REF_NODE) &&
7254 (cur->children->type != XML_ENTITY_NODE)) {
7255 cur = cur->children;
7256 continue;
7257 }
7258 }
7259 skip_children:
7260 if (cur->next != NULL) {
7261 cur = cur->next;
7262 continue;
7263 }
7264
7265 do {
7266 cur = cur->parent;
7267 if (cur == NULL)
7268 break;
7269 if (cur == root) {
7270 cur = NULL;
7271 break;
7272 }
7273 if (cur->next != NULL) {
7274 cur = cur->next;
7275 break;
7276 }
7277 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007278 }
7279 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007280 xmlUnlinkNode(delete);
7281 xmlFreeNode(delete);
7282 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007283 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007284}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007285
Daniel Veillardc5312d72003-02-21 17:14:10 +00007286/**
7287 * xmlRelaxNGCleanupDoc:
7288 * @ctxt: a Relax-NG parser context
7289 * @doc: an xmldocPtr document pointer
7290 *
7291 * Cleanup the document from unwanted nodes for parsing, resolve
7292 * Include and externalRef lookups.
7293 *
7294 * Returns the cleaned up document or NULL in case of error
7295 */
7296static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007297xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7298{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007299 xmlNodePtr root;
7300
7301 /*
7302 * Extract the root
7303 */
7304 root = xmlDocGetRootElement(doc);
7305 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007306 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7307 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007308 return (NULL);
7309 }
7310 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007311 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007312}
7313
7314/**
7315 * xmlRelaxNGParse:
7316 * @ctxt: a Relax-NG parser context
7317 *
7318 * parse a schema definition resource and build an internal
7319 * XML Shema struture which can be used to validate instances.
7320 * *WARNING* this interface is highly subject to change
7321 *
7322 * Returns the internal XML RelaxNG structure built from the resource or
7323 * NULL in case of error
7324 */
7325xmlRelaxNGPtr
7326xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7327{
7328 xmlRelaxNGPtr ret = NULL;
7329 xmlDocPtr doc;
7330 xmlNodePtr root;
7331
7332 xmlRelaxNGInitTypes();
7333
7334 if (ctxt == NULL)
7335 return (NULL);
7336
7337 /*
7338 * First step is to parse the input document into an DOM/Infoset
7339 */
7340 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007341 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007342 if (doc == NULL) {
7343 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7344 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7345 NULL);
7346 return (NULL);
7347 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007348 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007349 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007350 if (doc == NULL) {
7351 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7352 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7353 NULL);
7354 return (NULL);
7355 }
7356 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7357 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007358 } else if (ctxt->document != NULL) {
7359 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007360 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007361 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7362 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7363 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007364 }
7365 ctxt->document = doc;
7366
7367 /*
7368 * Some preprocessing of the document content
7369 */
7370 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7371 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007372 xmlFreeDoc(ctxt->document);
7373 ctxt->document = NULL;
7374 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007375 }
7376
Daniel Veillard6eadf632003-01-23 18:29:16 +00007377 /*
7378 * Then do the parsing for good
7379 */
7380 root = xmlDocGetRootElement(doc);
7381 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007382 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7383 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7384 ctxt->URL, NULL);
7385 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007386 return (NULL);
7387 }
7388 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007389 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007390 xmlFreeDoc(doc);
7391 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007392 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007393
7394 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007395 * Check the ref/defines links
7396 */
7397 /*
7398 * try to preprocess interleaves
7399 */
7400 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007401 xmlHashScan(ctxt->interleaves,
7402 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007403 }
7404
7405 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007406 * if there was a parsing error return NULL
7407 */
7408 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007409 xmlRelaxNGFree(ret);
7410 ctxt->document = NULL;
7411 xmlFreeDoc(doc);
7412 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007413 }
7414
7415 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007416 * try to compile (parts of) the schemas
7417 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007418 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7419 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007420 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007421
Daniel Veillard4c004142003-10-07 11:33:24 +00007422 def = xmlRelaxNGNewDefine(ctxt, NULL);
7423 if (def != NULL) {
7424 def->type = XML_RELAXNG_START;
7425 def->content = ret->topgrammar->start;
7426 ret->topgrammar->start = def;
7427 }
7428 }
7429 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007430 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007431
7432 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007433 * Transfer the pointer for cleanup at the schema level.
7434 */
7435 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007436 ctxt->document = NULL;
7437 ret->documents = ctxt->documents;
7438 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007439
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007440 ret->includes = ctxt->includes;
7441 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007442 ret->defNr = ctxt->defNr;
7443 ret->defTab = ctxt->defTab;
7444 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007445 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007446 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007447
7448 return (ret);
7449}
Daniel Veillard4c004142003-10-07 11:33:24 +00007450
Daniel Veillard6eadf632003-01-23 18:29:16 +00007451/**
7452 * xmlRelaxNGSetParserErrors:
7453 * @ctxt: a Relax-NG validation context
7454 * @err: the error callback
7455 * @warn: the warning callback
7456 * @ctx: contextual data for the callbacks
7457 *
7458 * Set the callback functions used to handle errors for a validation context
7459 */
7460void
7461xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007462 xmlRelaxNGValidityErrorFunc err,
7463 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7464{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007465 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007466 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007467 ctxt->error = err;
7468 ctxt->warning = warn;
7469 ctxt->userData = ctx;
7470}
Daniel Veillard409a8142003-07-18 15:16:57 +00007471
7472/**
7473 * xmlRelaxNGGetParserErrors:
7474 * @ctxt: a Relax-NG validation context
7475 * @err: the error callback result
7476 * @warn: the warning callback result
7477 * @ctx: contextual data for the callbacks result
7478 *
7479 * Get the callback information used to handle errors for a validation context
7480 *
7481 * Returns -1 in case of failure, 0 otherwise.
7482 */
7483int
7484xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007485 xmlRelaxNGValidityErrorFunc * err,
7486 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7487{
Daniel Veillard409a8142003-07-18 15:16:57 +00007488 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007489 return (-1);
7490 if (err != NULL)
7491 *err = ctxt->error;
7492 if (warn != NULL)
7493 *warn = ctxt->warning;
7494 if (ctx != NULL)
7495 *ctx = ctxt->userData;
7496 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007497}
7498
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007499#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007500
Daniel Veillard6eadf632003-01-23 18:29:16 +00007501/************************************************************************
7502 * *
7503 * Dump back a compiled form *
7504 * *
7505 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007506static void xmlRelaxNGDumpDefine(FILE * output,
7507 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007508
7509/**
7510 * xmlRelaxNGDumpDefines:
7511 * @output: the file output
7512 * @defines: a list of define structures
7513 *
7514 * Dump a RelaxNG structure back
7515 */
7516static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007517xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7518{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007519 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007520 xmlRelaxNGDumpDefine(output, defines);
7521 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007522 }
7523}
7524
7525/**
7526 * xmlRelaxNGDumpDefine:
7527 * @output: the file output
7528 * @define: a define structure
7529 *
7530 * Dump a RelaxNG structure back
7531 */
7532static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007533xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7534{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007535 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007536 return;
7537 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007538 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007539 fprintf(output, "<empty/>\n");
7540 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007541 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007542 fprintf(output, "<notAllowed/>\n");
7543 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007544 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007545 fprintf(output, "<text/>\n");
7546 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007547 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007548 fprintf(output, "<element>\n");
7549 if (define->name != NULL) {
7550 fprintf(output, "<name");
7551 if (define->ns != NULL)
7552 fprintf(output, " ns=\"%s\"", define->ns);
7553 fprintf(output, ">%s</name>\n", define->name);
7554 }
7555 xmlRelaxNGDumpDefines(output, define->attrs);
7556 xmlRelaxNGDumpDefines(output, define->content);
7557 fprintf(output, "</element>\n");
7558 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007559 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007560 fprintf(output, "<list>\n");
7561 xmlRelaxNGDumpDefines(output, define->content);
7562 fprintf(output, "</list>\n");
7563 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007564 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007565 fprintf(output, "<oneOrMore>\n");
7566 xmlRelaxNGDumpDefines(output, define->content);
7567 fprintf(output, "</oneOrMore>\n");
7568 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007569 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007570 fprintf(output, "<zeroOrMore>\n");
7571 xmlRelaxNGDumpDefines(output, define->content);
7572 fprintf(output, "</zeroOrMore>\n");
7573 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007574 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007575 fprintf(output, "<choice>\n");
7576 xmlRelaxNGDumpDefines(output, define->content);
7577 fprintf(output, "</choice>\n");
7578 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007579 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007580 fprintf(output, "<group>\n");
7581 xmlRelaxNGDumpDefines(output, define->content);
7582 fprintf(output, "</group>\n");
7583 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007584 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007585 fprintf(output, "<interleave>\n");
7586 xmlRelaxNGDumpDefines(output, define->content);
7587 fprintf(output, "</interleave>\n");
7588 break;
7589 case XML_RELAXNG_OPTIONAL:
7590 fprintf(output, "<optional>\n");
7591 xmlRelaxNGDumpDefines(output, define->content);
7592 fprintf(output, "</optional>\n");
7593 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007594 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007595 fprintf(output, "<attribute>\n");
7596 xmlRelaxNGDumpDefines(output, define->content);
7597 fprintf(output, "</attribute>\n");
7598 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007599 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007600 fprintf(output, "<define");
7601 if (define->name != NULL)
7602 fprintf(output, " name=\"%s\"", define->name);
7603 fprintf(output, ">\n");
7604 xmlRelaxNGDumpDefines(output, define->content);
7605 fprintf(output, "</define>\n");
7606 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007607 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007608 fprintf(output, "<ref");
7609 if (define->name != NULL)
7610 fprintf(output, " name=\"%s\"", define->name);
7611 fprintf(output, ">\n");
7612 xmlRelaxNGDumpDefines(output, define->content);
7613 fprintf(output, "</ref>\n");
7614 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007615 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007616 fprintf(output, "<parentRef");
7617 if (define->name != NULL)
7618 fprintf(output, " name=\"%s\"", define->name);
7619 fprintf(output, ">\n");
7620 xmlRelaxNGDumpDefines(output, define->content);
7621 fprintf(output, "</parentRef>\n");
7622 break;
7623 case XML_RELAXNG_EXTERNALREF:
7624 fprintf(output, "<externalRef>");
7625 xmlRelaxNGDumpDefines(output, define->content);
7626 fprintf(output, "</externalRef>\n");
7627 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007628 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007629 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007630 TODO break;
7631 case XML_RELAXNG_START:
7632 case XML_RELAXNG_EXCEPT:
7633 case XML_RELAXNG_PARAM:
7634 TODO break;
7635 case XML_RELAXNG_NOOP:
7636 xmlRelaxNGDumpDefines(output, define->content);
7637 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007638 }
7639}
Daniel Veillard4c004142003-10-07 11:33:24 +00007640
Daniel Veillard6eadf632003-01-23 18:29:16 +00007641/**
7642 * xmlRelaxNGDumpGrammar:
7643 * @output: the file output
7644 * @grammar: a grammar structure
7645 * @top: is this a top grammar
7646 *
7647 * Dump a RelaxNG structure back
7648 */
7649static void
7650xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7651{
7652 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007653 return;
7654
Daniel Veillard6eadf632003-01-23 18:29:16 +00007655 fprintf(output, "<grammar");
7656 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007657 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7658 switch (grammar->combine) {
7659 case XML_RELAXNG_COMBINE_UNDEFINED:
7660 break;
7661 case XML_RELAXNG_COMBINE_CHOICE:
7662 fprintf(output, " combine=\"choice\"");
7663 break;
7664 case XML_RELAXNG_COMBINE_INTERLEAVE:
7665 fprintf(output, " combine=\"interleave\"");
7666 break;
7667 default:
7668 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007669 }
7670 fprintf(output, ">\n");
7671 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007672 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007673 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007674 fprintf(output, "<start>\n");
7675 xmlRelaxNGDumpDefine(output, grammar->start);
7676 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007677 }
7678 /* TODO ? Dump the defines ? */
7679 fprintf(output, "</grammar>\n");
7680}
7681
7682/**
7683 * xmlRelaxNGDump:
7684 * @output: the file output
7685 * @schema: a schema structure
7686 *
7687 * Dump a RelaxNG structure back
7688 */
7689void
7690xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7691{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007692 if (output == NULL)
7693 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007694 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007695 fprintf(output, "RelaxNG empty or failed to compile\n");
7696 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007697 }
7698 fprintf(output, "RelaxNG: ");
7699 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007700 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007701 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007702 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007703 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007704 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007705 }
7706 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007707 fprintf(output, "RelaxNG has no top grammar\n");
7708 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007709 }
7710 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7711}
7712
Daniel Veillardfebcca42003-02-16 15:44:18 +00007713/**
7714 * xmlRelaxNGDumpTree:
7715 * @output: the file output
7716 * @schema: a schema structure
7717 *
7718 * Dump the transformed RelaxNG tree.
7719 */
7720void
7721xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7722{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007723 if (output == NULL)
7724 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007725 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007726 fprintf(output, "RelaxNG empty or failed to compile\n");
7727 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007728 }
7729 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007730 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007731 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007732 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007733 }
7734}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007735#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007736
Daniel Veillard6eadf632003-01-23 18:29:16 +00007737/************************************************************************
7738 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007739 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007740 * *
7741 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007742static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7743 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007744
7745/**
7746 * xmlRelaxNGValidateCompiledCallback:
7747 * @exec: the regular expression instance
7748 * @token: the token which matched
7749 * @transdata: callback data, the define for the subelement if available
7750 @ @inputdata: callback data, the Relax NG validation context
7751 *
7752 * Handle the callback and if needed validate the element children.
7753 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007754static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007755xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007756 const xmlChar * token,
7757 void *transdata, void *inputdata)
7758{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007759 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7760 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7761 int ret;
7762
7763#ifdef DEBUG_COMPILE
7764 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007765 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007766#endif
7767 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007768 fprintf(stderr, "callback on %s missing context\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 }
7773 if (define == NULL) {
7774 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007775 return;
7776 fprintf(stderr, "callback on %s missing define\n", token);
7777 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7778 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7779 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007780 }
7781 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007782 fprintf(stderr, "callback on %s missing info\n", token);
7783 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7784 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7785 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007786 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007787 fprintf(stderr, "callback on %s define is not element\n", token);
7788 if (ctxt->errNo == XML_RELAXNG_OK)
7789 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7790 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007791 }
7792 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007793 if (ret != 0)
7794 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007795}
7796
7797/**
7798 * xmlRelaxNGValidateCompiledContent:
7799 * @ctxt: the RelaxNG validation context
7800 * @regexp: the regular expression as compiled
7801 * @content: list of children to test against the regexp
7802 *
7803 * Validate the content model of an element or start using the regexp
7804 *
7805 * Returns 0 in case of success, -1 in case of error.
7806 */
7807static int
7808xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007809 xmlRegexpPtr regexp, xmlNodePtr content)
7810{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007811 xmlRegExecCtxtPtr exec;
7812 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007813 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007814 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007815
7816 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007817 return (-1);
7818 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007819 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007820 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007821 cur = content;
7822 while (cur != NULL) {
7823 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007824 switch (cur->type) {
7825 case XML_TEXT_NODE:
7826 case XML_CDATA_SECTION_NODE:
7827 if (xmlIsBlankNode(cur))
7828 break;
7829 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7830 if (ret < 0) {
7831 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7832 cur->parent->name);
7833 }
7834 break;
7835 case XML_ELEMENT_NODE:
7836 if (cur->ns != NULL) {
7837 ret = xmlRegExecPushString2(exec, cur->name,
7838 cur->ns->href, ctxt);
7839 } else {
7840 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7841 }
7842 if (ret < 0) {
7843 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7844 }
7845 break;
7846 default:
7847 break;
7848 }
7849 if (ret < 0)
7850 break;
7851 /*
7852 * Switch to next element
7853 */
7854 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007855 }
7856 ret = xmlRegExecPushString(exec, NULL, NULL);
7857 if (ret == 1) {
7858 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007859 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007860 } else if (ret == 0) {
7861 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007862 * TODO: get some of the names needed to exit the current state of exec
7863 */
7864 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7865 ret = -1;
7866 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7867 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007868 } else {
7869 ret = -1;
7870 }
7871 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007872 /*
7873 * There might be content model errors outside of the pure
7874 * regexp validation, e.g. for attribute values.
7875 */
7876 if ((ret == 0) && (ctxt->perr != 0)) {
7877 ret = ctxt->perr;
7878 }
7879 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007880 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007881}
7882
7883/************************************************************************
7884 * *
7885 * Progressive validation of when possible *
7886 * *
7887 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007888static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7889 xmlRelaxNGDefinePtr defines);
7890static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007891 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007892static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007893
7894/**
7895 * xmlRelaxNGElemPush:
7896 * @ctxt: the validation context
7897 * @exec: the regexp runtime for the new content model
7898 *
7899 * Push a new regexp for the current node content model on the stack
7900 *
7901 * Returns 0 in case of success and -1 in case of error.
7902 */
7903static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007904xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7905{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007906 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007907 ctxt->elemMax = 10;
7908 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7909 sizeof
7910 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007911 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007912 xmlRngVErrMemory(ctxt, "validating\n");
7913 return (-1);
7914 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007915 }
7916 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007917 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007918 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007919 ctxt->elemMax *
7920 sizeof
7921 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007922 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007923 xmlRngVErrMemory(ctxt, "validating\n");
7924 return (-1);
7925 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007926 }
7927 ctxt->elemTab[ctxt->elemNr++] = exec;
7928 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007929 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007930}
7931
7932/**
7933 * xmlRelaxNGElemPop:
7934 * @ctxt: the validation context
7935 *
7936 * Pop the regexp of the current node content model from the stack
7937 *
7938 * Returns the exec or NULL if empty
7939 */
7940static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007941xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7942{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007943 xmlRegExecCtxtPtr ret;
7944
Daniel Veillard4c004142003-10-07 11:33:24 +00007945 if (ctxt->elemNr <= 0)
7946 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007947 ctxt->elemNr--;
7948 ret = ctxt->elemTab[ctxt->elemNr];
7949 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007950 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007951 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7952 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007953 ctxt->elem = NULL;
7954 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007955}
7956
7957/**
7958 * xmlRelaxNGValidateProgressiveCallback:
7959 * @exec: the regular expression instance
7960 * @token: the token which matched
7961 * @transdata: callback data, the define for the subelement if available
7962 @ @inputdata: callback data, the Relax NG validation context
7963 *
7964 * Handle the callback and if needed validate the element children.
7965 * some of the in/out informations are passed via the context in @inputdata.
7966 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007967static void
7968xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7969 ATTRIBUTE_UNUSED,
7970 const xmlChar * token,
7971 void *transdata, void *inputdata)
7972{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007973 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7974 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007975 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007976 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007977 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007978
7979#ifdef DEBUG_PROGRESSIVE
7980 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007981 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007982#endif
7983 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007984 fprintf(stderr, "callback on %s missing context\n", token);
7985 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007986 }
7987 ctxt->pstate = 1;
7988 if (define == NULL) {
7989 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007990 return;
7991 fprintf(stderr, "callback on %s missing define\n", token);
7992 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7993 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7994 ctxt->pstate = -1;
7995 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007996 }
7997 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007998 fprintf(stderr, "callback on %s missing info\n", token);
7999 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8000 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8001 ctxt->pstate = -1;
8002 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008003 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008004 fprintf(stderr, "callback on %s define is not element\n", token);
8005 if (ctxt->errNo == XML_RELAXNG_OK)
8006 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8007 ctxt->pstate = -1;
8008 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008009 }
8010 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008011 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8012 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8013 xmlRelaxNGDumpValidError(ctxt);
8014 ctxt->pstate = -1;
8015 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008016 }
8017 if (define->contModel == NULL) {
8018 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008019 * this node cannot be validated in a streamable fashion
8020 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00008021#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008022 xmlGenericError(xmlGenericErrorContext,
8023 "Element '%s' validation is not streamable\n",
8024 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008025#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008026 ctxt->pstate = 0;
8027 ctxt->pdef = define;
8028 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008029 }
8030 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008031 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008032 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008033 ctxt->pstate = -1;
8034 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008035 }
8036 xmlRelaxNGElemPush(ctxt, exec);
8037
8038 /*
8039 * Validate the attributes part of the content.
8040 */
8041 state = xmlRelaxNGNewValidState(ctxt, node);
8042 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008043 ctxt->pstate = -1;
8044 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008045 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008046 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008047 ctxt->state = state;
8048 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008049 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8050 if (ret != 0) {
8051 ctxt->pstate = -1;
8052 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8053 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008054 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008055 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008056 ctxt->state->seq = NULL;
8057 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8058 if (ret != 0) {
8059 ctxt->pstate = -1;
8060 }
8061 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008062 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008063 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008064
8065 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008066
Daniel Veillard4c004142003-10-07 11:33:24 +00008067 for (i = 0; i < ctxt->states->nbState; i++) {
8068 state = ctxt->states->tabState[i];
8069 ctxt->state = state;
8070 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008071
Daniel Veillard4c004142003-10-07 11:33:24 +00008072 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8073 tmp = 0;
8074 break;
8075 }
8076 }
8077 if (tmp != 0) {
8078 /*
8079 * validation error, log the message for the "best" one
8080 */
8081 ctxt->flags |= FLAGS_IGNORABLE;
8082 xmlRelaxNGLogBestError(ctxt);
8083 }
8084 for (i = 0; i < ctxt->states->nbState; i++) {
8085 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8086 }
8087 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8088 ctxt->states = NULL;
8089 if ((ret == 0) && (tmp == -1))
8090 ctxt->pstate = -1;
8091 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008092 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008093 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008094 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8095 xmlRelaxNGDumpValidError(ctxt);
8096 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008097 }
8098 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008099}
8100
8101/**
8102 * xmlRelaxNGValidatePushElement:
8103 * @ctxt: the validation context
8104 * @doc: a document instance
8105 * @elem: an element instance
8106 *
8107 * Push a new element start on the RelaxNG validation stack.
8108 *
8109 * returns 1 if no validation problem was found or 0 if validating the
8110 * element requires a full node, and -1 in case of error.
8111 */
8112int
Daniel Veillard33300b42003-04-17 09:09:19 +00008113xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8114 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008115 xmlNodePtr elem)
8116{
8117 int ret = 1;
8118
8119 if ((ctxt == NULL) || (elem == NULL))
8120 return (-1);
8121
8122#ifdef DEBUG_PROGRESSIVE
8123 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8124#endif
8125 if (ctxt->elem == 0) {
8126 xmlRelaxNGPtr schema;
8127 xmlRelaxNGGrammarPtr grammar;
8128 xmlRegExecCtxtPtr exec;
8129 xmlRelaxNGDefinePtr define;
8130
8131 schema = ctxt->schema;
8132 if (schema == NULL) {
8133 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8134 return (-1);
8135 }
8136 grammar = schema->topgrammar;
8137 if ((grammar == NULL) || (grammar->start == NULL)) {
8138 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8139 return (-1);
8140 }
8141 define = grammar->start;
8142 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008143 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008144 return (0);
8145 }
8146 exec = xmlRegNewExecCtxt(define->contModel,
8147 xmlRelaxNGValidateProgressiveCallback,
8148 ctxt);
8149 if (exec == NULL) {
8150 return (-1);
8151 }
8152 xmlRelaxNGElemPush(ctxt, exec);
8153 }
8154 ctxt->pnode = elem;
8155 ctxt->pstate = 0;
8156 if (elem->ns != NULL) {
8157 ret =
8158 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8159 ctxt);
8160 } else {
8161 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8162 }
8163 if (ret < 0) {
8164 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8165 } else {
8166 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008167 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008168 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008169 ret = -1;
8170 else
8171 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008172 }
8173#ifdef DEBUG_PROGRESSIVE
8174 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008175 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8176 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008177#endif
8178 return (ret);
8179}
8180
8181/**
8182 * xmlRelaxNGValidatePushCData:
8183 * @ctxt: the RelaxNG validation context
8184 * @data: some character data read
8185 * @len: the lenght of the data
8186 *
8187 * check the CData parsed for validation in the current stack
8188 *
8189 * returns 1 if no validation problem was found or -1 otherwise
8190 */
8191int
8192xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008193 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008194{
8195 int ret = 1;
8196
8197 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8198 return (-1);
8199
8200#ifdef DEBUG_PROGRESSIVE
8201 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8202#endif
8203
8204 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008205 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008206 break;
8207 data++;
8208 }
8209 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008210 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008211
8212 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8213 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008214 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008215#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008216 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008217#endif
8218
Daniel Veillard4c004142003-10-07 11:33:24 +00008219 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008220 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008221 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008222}
8223
8224/**
8225 * xmlRelaxNGValidatePopElement:
8226 * @ctxt: the RelaxNG validation context
8227 * @doc: a document instance
8228 * @elem: an element instance
8229 *
8230 * Pop the element end from the RelaxNG validation stack.
8231 *
8232 * returns 1 if no validation problem was found or 0 otherwise
8233 */
8234int
8235xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8236 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008237 xmlNodePtr elem)
8238{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008239 int ret;
8240 xmlRegExecCtxtPtr exec;
8241
Daniel Veillard4c004142003-10-07 11:33:24 +00008242 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8243 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008244#ifdef DEBUG_PROGRESSIVE
8245 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8246#endif
8247 /*
8248 * verify that we reached a terminal state of the content model.
8249 */
8250 exec = xmlRelaxNGElemPop(ctxt);
8251 ret = xmlRegExecPushString(exec, NULL, NULL);
8252 if (ret == 0) {
8253 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008254 * TODO: get some of the names needed to exit the current state of exec
8255 */
8256 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8257 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008258 } else if (ret < 0) {
8259 ret = -1;
8260 } else {
8261 ret = 1;
8262 }
8263 xmlRegFreeExecCtxt(exec);
8264#ifdef DEBUG_PROGRESSIVE
8265 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008266 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8267 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008268#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008269 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008270}
8271
8272/**
8273 * xmlRelaxNGValidateFullElement:
8274 * @ctxt: the validation context
8275 * @doc: a document instance
8276 * @elem: an element instance
8277 *
8278 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8279 * 0 and the content of the node has been expanded.
8280 *
8281 * returns 1 if no validation problem was found or -1 in case of error.
8282 */
8283int
Daniel Veillard33300b42003-04-17 09:09:19 +00008284xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8285 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008286 xmlNodePtr elem)
8287{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008288 int ret;
8289 xmlRelaxNGValidStatePtr state;
8290
Daniel Veillard4c004142003-10-07 11:33:24 +00008291 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8292 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008293#ifdef DEBUG_PROGRESSIVE
8294 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8295#endif
8296 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8297 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008298 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008299 }
8300 state->seq = elem;
8301 ctxt->state = state;
8302 ctxt->errNo = XML_RELAXNG_OK;
8303 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008304 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8305 ret = -1;
8306 else
8307 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008308 xmlRelaxNGFreeValidState(ctxt, state);
8309 ctxt->state = NULL;
8310#ifdef DEBUG_PROGRESSIVE
8311 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008312 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8313 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008314#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008315 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008316}
8317
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008318/************************************************************************
8319 * *
8320 * Generic interpreted validation implementation *
8321 * *
8322 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008323static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8324 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008325
8326/**
8327 * xmlRelaxNGSkipIgnored:
8328 * @ctxt: a schema validation context
8329 * @node: the top node.
8330 *
8331 * Skip ignorable nodes in that context
8332 *
8333 * Returns the new sibling or NULL in case of error.
8334 */
8335static xmlNodePtr
8336xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008337 xmlNodePtr node)
8338{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008339 /*
8340 * TODO complete and handle entities
8341 */
8342 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008343 ((node->type == XML_COMMENT_NODE) ||
8344 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008345 (node->type == XML_XINCLUDE_START) ||
8346 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008347 (((node->type == XML_TEXT_NODE) ||
8348 (node->type == XML_CDATA_SECTION_NODE)) &&
8349 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8350 (IS_BLANK_NODE(node)))))) {
8351 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008352 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008353 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008354}
8355
8356/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008357 * xmlRelaxNGNormalize:
8358 * @ctxt: a schema validation context
8359 * @str: the string to normalize
8360 *
8361 * Implements the normalizeWhiteSpace( s ) function from
8362 * section 6.2.9 of the spec
8363 *
8364 * Returns the new string or NULL in case of error.
8365 */
8366static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008367xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8368{
Daniel Veillardedc91922003-01-26 00:52:04 +00008369 xmlChar *ret, *p;
8370 const xmlChar *tmp;
8371 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008372
Daniel Veillardedc91922003-01-26 00:52:04 +00008373 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008374 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008375 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008376 while (*tmp != 0)
8377 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008378 len = tmp - str;
8379
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008380 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008381 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008382 xmlRngVErrMemory(ctxt, "validating\n");
8383 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008384 }
8385 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008386 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008387 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008388 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008389 if (IS_BLANK_CH(*str)) {
8390 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008391 str++;
8392 if (*str == 0)
8393 break;
8394 *p++ = ' ';
8395 } else
8396 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008397 }
8398 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008399 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008400}
8401
8402/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008403 * xmlRelaxNGValidateDatatype:
8404 * @ctxt: a Relax-NG validation context
8405 * @value: the string value
8406 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008407 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008408 *
8409 * Validate the given value against the dataype
8410 *
8411 * Returns 0 if the validation succeeded or an error code.
8412 */
8413static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008414xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8415 const xmlChar * value,
8416 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8417{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008418 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008419 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008420 void *result = NULL;
8421 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008422
8423 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008424 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008425 }
8426 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008427 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008428 if ((define->attrs != NULL) &&
8429 (define->attrs->type == XML_RELAXNG_PARAM)) {
8430 ret =
8431 lib->check(lib->data, define->name, value, &result, node);
8432 } else {
8433 ret = lib->check(lib->data, define->name, value, NULL, node);
8434 }
8435 } else
8436 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008437 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008438 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8439 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8440 lib->freef(lib->data, result);
8441 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008442 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008443 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008444 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008445 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008446 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008447 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8448 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008449 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008450 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008451 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008452 if (lib->facet != NULL) {
8453 tmp = lib->facet(lib->data, define->name, cur->name,
8454 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008455 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008456 ret = -1;
8457 }
8458 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008459 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008460 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008461 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008462
Daniel Veillard4c004142003-10-07 11:33:24 +00008463 oldvalue = ctxt->state->value;
8464 oldendvalue = ctxt->state->endvalue;
8465 ctxt->state->value = (xmlChar *) value;
8466 ctxt->state->endvalue = NULL;
8467 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8468 ctxt->state->value = (xmlChar *) oldvalue;
8469 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008470 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008471 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008472 lib->freef(lib->data, result);
8473 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008474}
8475
8476/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008477 * xmlRelaxNGNextValue:
8478 * @ctxt: a Relax-NG validation context
8479 *
8480 * Skip to the next value when validating within a list
8481 *
8482 * Returns 0 if the operation succeeded or an error code.
8483 */
8484static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008485xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8486{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008487 xmlChar *cur;
8488
8489 cur = ctxt->state->value;
8490 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008491 ctxt->state->value = NULL;
8492 ctxt->state->endvalue = NULL;
8493 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008494 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008495 while (*cur != 0)
8496 cur++;
8497 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8498 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008499 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008500 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008501 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008502 ctxt->state->value = cur;
8503 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008504}
8505
8506/**
8507 * xmlRelaxNGValidateValueList:
8508 * @ctxt: a Relax-NG validation context
8509 * @defines: the list of definitions to verify
8510 *
8511 * Validate the given set of definitions for the current value
8512 *
8513 * Returns 0 if the validation succeeded or an error code.
8514 */
8515static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008516xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8517 xmlRelaxNGDefinePtr defines)
8518{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008519 int ret = 0;
8520
8521 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008522 ret = xmlRelaxNGValidateValue(ctxt, defines);
8523 if (ret != 0)
8524 break;
8525 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008526 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008527 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008528}
8529
8530/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008531 * xmlRelaxNGValidateValue:
8532 * @ctxt: a Relax-NG validation context
8533 * @define: the definition to verify
8534 *
8535 * Validate the given definition for the current value
8536 *
8537 * Returns 0 if the validation succeeded or an error code.
8538 */
8539static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008540xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8541 xmlRelaxNGDefinePtr define)
8542{
Daniel Veillardedc91922003-01-26 00:52:04 +00008543 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008544 xmlChar *value;
8545
8546 value = ctxt->state->value;
8547 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008548 case XML_RELAXNG_EMPTY:{
8549 if ((value != NULL) && (value[0] != 0)) {
8550 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008551
William M. Brack76e95df2003-10-18 16:20:14 +00008552 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008553 idx++;
8554 if (value[idx] != 0)
8555 ret = -1;
8556 }
8557 break;
8558 }
8559 case XML_RELAXNG_TEXT:
8560 break;
8561 case XML_RELAXNG_VALUE:{
8562 if (!xmlStrEqual(value, define->value)) {
8563 if (define->name != NULL) {
8564 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008565
Daniel Veillard4c004142003-10-07 11:33:24 +00008566 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8567 if ((lib != NULL) && (lib->comp != NULL)) {
8568 ret = lib->comp(lib->data, define->name,
8569 define->value, define->node,
8570 (void *) define->attrs,
8571 value, ctxt->state->node);
8572 } else
8573 ret = -1;
8574 if (ret < 0) {
8575 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8576 define->name);
8577 return (-1);
8578 } else if (ret == 1) {
8579 ret = 0;
8580 } else {
8581 ret = -1;
8582 }
8583 } else {
8584 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008585
Daniel Veillard4c004142003-10-07 11:33:24 +00008586 /*
8587 * TODO: trivial optimizations are possible by
8588 * computing at compile-time
8589 */
8590 nval = xmlRelaxNGNormalize(ctxt, define->value);
8591 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008592
Daniel Veillard4c004142003-10-07 11:33:24 +00008593 if ((nval == NULL) || (nvalue == NULL) ||
8594 (!xmlStrEqual(nval, nvalue)))
8595 ret = -1;
8596 if (nval != NULL)
8597 xmlFree(nval);
8598 if (nvalue != NULL)
8599 xmlFree(nvalue);
8600 }
8601 }
8602 if (ret == 0)
8603 xmlRelaxNGNextValue(ctxt);
8604 break;
8605 }
8606 case XML_RELAXNG_DATATYPE:{
8607 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8608 ctxt->state->seq);
8609 if (ret == 0)
8610 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008611
Daniel Veillard4c004142003-10-07 11:33:24 +00008612 break;
8613 }
8614 case XML_RELAXNG_CHOICE:{
8615 xmlRelaxNGDefinePtr list = define->content;
8616 xmlChar *oldvalue;
8617
8618 oldflags = ctxt->flags;
8619 ctxt->flags |= FLAGS_IGNORABLE;
8620
8621 oldvalue = ctxt->state->value;
8622 while (list != NULL) {
8623 ret = xmlRelaxNGValidateValue(ctxt, list);
8624 if (ret == 0) {
8625 break;
8626 }
8627 ctxt->state->value = oldvalue;
8628 list = list->next;
8629 }
8630 ctxt->flags = oldflags;
8631 if (ret != 0) {
8632 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8633 xmlRelaxNGDumpValidError(ctxt);
8634 } else {
8635 if (ctxt->errNr > 0)
8636 xmlRelaxNGPopErrors(ctxt, 0);
8637 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008638 break;
8639 }
8640 case XML_RELAXNG_LIST:{
8641 xmlRelaxNGDefinePtr list = define->content;
8642 xmlChar *oldvalue, *oldend, *val, *cur;
8643
Daniel Veillard416589a2003-02-17 17:25:42 +00008644#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008645 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008646#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008647
Daniel Veillard4c004142003-10-07 11:33:24 +00008648 oldvalue = ctxt->state->value;
8649 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008650
Daniel Veillard4c004142003-10-07 11:33:24 +00008651 val = xmlStrdup(oldvalue);
8652 if (val == NULL) {
8653 val = xmlStrdup(BAD_CAST "");
8654 }
8655 if (val == NULL) {
8656 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8657 return (-1);
8658 }
8659 cur = val;
8660 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008661 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008662 *cur = 0;
8663 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008664#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008665 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008666#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008667 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008668 *cur++ = 0;
8669 } else
8670 cur++;
8671 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008672#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008673 xmlGenericError(xmlGenericErrorContext,
8674 "list value: '%s' found %d items\n",
8675 oldvalue, nb_values);
8676 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008677#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008678 ctxt->state->endvalue = cur;
8679 cur = val;
8680 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8681 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008682
Daniel Veillard4c004142003-10-07 11:33:24 +00008683 ctxt->state->value = cur;
8684
8685 while (list != NULL) {
8686 if (ctxt->state->value == ctxt->state->endvalue)
8687 ctxt->state->value = NULL;
8688 ret = xmlRelaxNGValidateValue(ctxt, list);
8689 if (ret != 0) {
8690#ifdef DEBUG_LIST
8691 xmlGenericError(xmlGenericErrorContext,
8692 "Failed to validate value: '%s' with %d rule\n",
8693 ctxt->state->value, nb_values);
8694#endif
8695 break;
8696 }
8697#ifdef DEBUG_LIST
8698 nb_values++;
8699#endif
8700 list = list->next;
8701 }
8702
8703 if ((ret == 0) && (ctxt->state->value != NULL) &&
8704 (ctxt->state->value != ctxt->state->endvalue)) {
8705 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8706 ctxt->state->value);
8707 ret = -1;
8708 }
8709 xmlFree(val);
8710 ctxt->state->value = oldvalue;
8711 ctxt->state->endvalue = oldend;
8712 break;
8713 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008714 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008715 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8716 if (ret != 0) {
8717 break;
8718 }
8719 /* no break on purpose */
8720 case XML_RELAXNG_ZEROORMORE:{
8721 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008722
Daniel Veillard4c004142003-10-07 11:33:24 +00008723 oldflags = ctxt->flags;
8724 ctxt->flags |= FLAGS_IGNORABLE;
8725 cur = ctxt->state->value;
8726 temp = NULL;
8727 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8728 (temp != cur)) {
8729 temp = cur;
8730 ret =
8731 xmlRelaxNGValidateValueList(ctxt, define->content);
8732 if (ret != 0) {
8733 ctxt->state->value = temp;
8734 ret = 0;
8735 break;
8736 }
8737 cur = ctxt->state->value;
8738 }
8739 ctxt->flags = oldflags;
8740 if (ret != 0) {
8741 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8742 xmlRelaxNGDumpValidError(ctxt);
8743 } else {
8744 if (ctxt->errNr > 0)
8745 xmlRelaxNGPopErrors(ctxt, 0);
8746 }
8747 break;
8748 }
8749 case XML_RELAXNG_EXCEPT:{
8750 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008751
Daniel Veillard4c004142003-10-07 11:33:24 +00008752 list = define->content;
8753 while (list != NULL) {
8754 ret = xmlRelaxNGValidateValue(ctxt, list);
8755 if (ret == 0) {
8756 ret = -1;
8757 break;
8758 } else
8759 ret = 0;
8760 list = list->next;
8761 }
8762 break;
8763 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008764 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008765 case XML_RELAXNG_GROUP:{
8766 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008767
Daniel Veillard4c004142003-10-07 11:33:24 +00008768 list = define->content;
8769 while (list != NULL) {
8770 ret = xmlRelaxNGValidateValue(ctxt, list);
8771 if (ret != 0) {
8772 ret = -1;
8773 break;
8774 } else
8775 ret = 0;
8776 list = list->next;
8777 }
8778 break;
8779 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008780 case XML_RELAXNG_REF:
8781 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008782 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8783 break;
8784 default:
8785 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008786 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008787 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008788}
8789
8790/**
8791 * xmlRelaxNGValidateValueContent:
8792 * @ctxt: a Relax-NG validation context
8793 * @defines: the list of definitions to verify
8794 *
8795 * Validate the given definitions for the current value
8796 *
8797 * Returns 0 if the validation succeeded or an error code.
8798 */
8799static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008800xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8801 xmlRelaxNGDefinePtr defines)
8802{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008803 int ret = 0;
8804
8805 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008806 ret = xmlRelaxNGValidateValue(ctxt, defines);
8807 if (ret != 0)
8808 break;
8809 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008810 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008811 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008812}
8813
8814/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008815 * xmlRelaxNGAttributeMatch:
8816 * @ctxt: a Relax-NG validation context
8817 * @define: the definition to check
8818 * @prop: the attribute
8819 *
8820 * Check if the attribute matches the definition nameClass
8821 *
8822 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8823 */
8824static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008825xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8826 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8827{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008828 int ret;
8829
8830 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008831 if (!xmlStrEqual(define->name, prop->name))
8832 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008833 }
8834 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008835 if (define->ns[0] == 0) {
8836 if (prop->ns != NULL)
8837 return (0);
8838 } else {
8839 if ((prop->ns == NULL) ||
8840 (!xmlStrEqual(define->ns, prop->ns->href)))
8841 return (0);
8842 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008843 }
8844 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008845 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008846 define = define->nameClass;
8847 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008848 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008849
Daniel Veillard4c004142003-10-07 11:33:24 +00008850 list = define->content;
8851 while (list != NULL) {
8852 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8853 if (ret == 1)
8854 return (0);
8855 if (ret < 0)
8856 return (ret);
8857 list = list->next;
8858 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008859 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008860 TODO}
8861 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008862}
8863
8864/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008865 * xmlRelaxNGValidateAttribute:
8866 * @ctxt: a Relax-NG validation context
8867 * @define: the definition to verify
8868 *
8869 * Validate the given attribute definition for that node
8870 *
8871 * Returns 0 if the validation succeeded or an error code.
8872 */
8873static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008874xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8875 xmlRelaxNGDefinePtr define)
8876{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008877 int ret = 0, i;
8878 xmlChar *value, *oldvalue;
8879 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008880 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008881
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008882 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008883 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008884 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008885 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8886 tmp = ctxt->state->attrs[i];
8887 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8888 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8889 (tmp->ns == NULL)) ||
8890 ((tmp->ns != NULL) &&
8891 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8892 prop = tmp;
8893 break;
8894 }
8895 }
8896 }
8897 if (prop != NULL) {
8898 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8899 oldvalue = ctxt->state->value;
8900 oldseq = ctxt->state->seq;
8901 ctxt->state->seq = (xmlNodePtr) prop;
8902 ctxt->state->value = value;
8903 ctxt->state->endvalue = NULL;
8904 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8905 if (ctxt->state->value != NULL)
8906 value = ctxt->state->value;
8907 if (value != NULL)
8908 xmlFree(value);
8909 ctxt->state->value = oldvalue;
8910 ctxt->state->seq = oldseq;
8911 if (ret == 0) {
8912 /*
8913 * flag the attribute as processed
8914 */
8915 ctxt->state->attrs[i] = NULL;
8916 ctxt->state->nbAttrLeft--;
8917 }
8918 } else {
8919 ret = -1;
8920 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008921#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008922 xmlGenericError(xmlGenericErrorContext,
8923 "xmlRelaxNGValidateAttribute(%s): %d\n",
8924 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008925#endif
8926 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008927 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8928 tmp = ctxt->state->attrs[i];
8929 if ((tmp != NULL) &&
8930 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8931 prop = tmp;
8932 break;
8933 }
8934 }
8935 if (prop != NULL) {
8936 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8937 oldvalue = ctxt->state->value;
8938 oldseq = ctxt->state->seq;
8939 ctxt->state->seq = (xmlNodePtr) prop;
8940 ctxt->state->value = value;
8941 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8942 if (ctxt->state->value != NULL)
8943 value = ctxt->state->value;
8944 if (value != NULL)
8945 xmlFree(value);
8946 ctxt->state->value = oldvalue;
8947 ctxt->state->seq = oldseq;
8948 if (ret == 0) {
8949 /*
8950 * flag the attribute as processed
8951 */
8952 ctxt->state->attrs[i] = NULL;
8953 ctxt->state->nbAttrLeft--;
8954 }
8955 } else {
8956 ret = -1;
8957 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008958#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008959 if (define->ns != NULL) {
8960 xmlGenericError(xmlGenericErrorContext,
8961 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8962 define->ns, ret);
8963 } else {
8964 xmlGenericError(xmlGenericErrorContext,
8965 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8966 ret);
8967 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008968#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008969 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008970
8971 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008972}
8973
8974/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008975 * xmlRelaxNGValidateAttributeList:
8976 * @ctxt: a Relax-NG validation context
8977 * @define: the list of definition to verify
8978 *
8979 * Validate the given node against the list of attribute definitions
8980 *
8981 * Returns 0 if the validation succeeded or an error code.
8982 */
8983static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008984xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8985 xmlRelaxNGDefinePtr defines)
8986{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008987 int ret = 0, res;
8988 int needmore = 0;
8989 xmlRelaxNGDefinePtr cur;
8990
8991 cur = defines;
8992 while (cur != NULL) {
8993 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008994 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8995 ret = -1;
8996 } else
8997 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008998 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008999 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009000 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00009001 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009002 cur = defines;
9003 while (cur != NULL) {
9004 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009005 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9006 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9007 if (res < 0)
9008 ret = -1;
9009 } else {
9010 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9011 return (-1);
9012 }
9013 if (res == -1) /* continues on -2 */
9014 break;
9015 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009016 cur = cur->next;
9017 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009018
9019 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009020}
9021
9022/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009023 * xmlRelaxNGNodeMatchesList:
9024 * @node: the node
9025 * @list: a NULL terminated array of definitions
9026 *
9027 * Check if a node can be matched by one of the definitions
9028 *
9029 * Returns 1 if matches 0 otherwise
9030 */
9031static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009032xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9033{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009034 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009035 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009036
9037 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009038 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009039
9040 cur = list[i++];
9041 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009042 if ((node->type == XML_ELEMENT_NODE) &&
9043 (cur->type == XML_RELAXNG_ELEMENT)) {
9044 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9045 if (tmp == 1)
9046 return (1);
9047 } else if (((node->type == XML_TEXT_NODE) ||
9048 (node->type == XML_CDATA_SECTION_NODE)) &&
9049 (cur->type == XML_RELAXNG_TEXT)) {
9050 return (1);
9051 }
9052 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009053 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009054 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009055}
9056
9057/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009058 * xmlRelaxNGValidateInterleave:
9059 * @ctxt: a Relax-NG validation context
9060 * @define: the definition to verify
9061 *
9062 * Validate an interleave definition for a node.
9063 *
9064 * Returns 0 if the validation succeeded or an error code.
9065 */
9066static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009067xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9068 xmlRelaxNGDefinePtr define)
9069{
William M. Brack779af002003-08-01 15:55:39 +00009070 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009071 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009072 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009073
9074 xmlRelaxNGValidStatePtr oldstate;
9075 xmlRelaxNGPartitionPtr partitions;
9076 xmlRelaxNGInterleaveGroupPtr group = NULL;
9077 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9078 xmlNodePtr *list = NULL, *lasts = NULL;
9079
9080 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009081 partitions = (xmlRelaxNGPartitionPtr) define->data;
9082 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009083 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009084 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9085 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009086 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009087 /*
9088 * Optimizations for MIXED
9089 */
9090 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009091 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009092 ctxt->flags |= FLAGS_MIXED_CONTENT;
9093 if (nbgroups == 2) {
9094 /*
9095 * this is a pure <mixed> case
9096 */
9097 if (ctxt->state != NULL)
9098 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9099 ctxt->state->seq);
9100 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9101 ret = xmlRelaxNGValidateDefinition(ctxt,
9102 partitions->groups[1]->
9103 rule);
9104 else
9105 ret = xmlRelaxNGValidateDefinition(ctxt,
9106 partitions->groups[0]->
9107 rule);
9108 if (ret == 0) {
9109 if (ctxt->state != NULL)
9110 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9111 ctxt->state->
9112 seq);
9113 }
9114 ctxt->flags = oldflags;
9115 return (ret);
9116 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009117 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009118
9119 /*
9120 * Build arrays to store the first and last node of the chain
9121 * pertaining to each group
9122 */
9123 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9124 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009125 xmlRngVErrMemory(ctxt, "validating\n");
9126 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009127 }
9128 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9129 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9130 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009131 xmlRngVErrMemory(ctxt, "validating\n");
9132 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009133 }
9134 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9135
9136 /*
9137 * Walk the sequence of children finding the right group and
9138 * sorting them in sequences.
9139 */
9140 cur = ctxt->state->seq;
9141 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9142 start = cur;
9143 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009144 ctxt->state->seq = cur;
9145 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009146 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009147 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009148
Daniel Veillard4c004142003-10-07 11:33:24 +00009149 if ((cur->type == XML_TEXT_NODE) ||
9150 (cur->type == XML_CDATA_SECTION_NODE)) {
9151 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9152 NULL);
9153 } else if (cur->type == XML_ELEMENT_NODE) {
9154 if (cur->ns != NULL) {
9155 tmp = xmlHashLookup2(partitions->triage, cur->name,
9156 cur->ns->href);
9157 if (tmp == NULL)
9158 tmp = xmlHashLookup2(partitions->triage,
9159 BAD_CAST "#any",
9160 cur->ns->href);
9161 } else
9162 tmp =
9163 xmlHashLookup2(partitions->triage, cur->name,
9164 NULL);
9165 if (tmp == NULL)
9166 tmp =
9167 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9168 NULL);
9169 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009170
Daniel Veillard4c004142003-10-07 11:33:24 +00009171 if (tmp == NULL) {
9172 i = nbgroups;
9173 } else {
9174 i = ((long) tmp) - 1;
9175 if (partitions->flags & IS_NEEDCHECK) {
9176 group = partitions->groups[i];
9177 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9178 i = nbgroups;
9179 }
9180 }
9181 } else {
9182 for (i = 0; i < nbgroups; i++) {
9183 group = partitions->groups[i];
9184 if (group == NULL)
9185 continue;
9186 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9187 break;
9188 }
9189 }
9190 /*
9191 * We break as soon as an element not matched is found
9192 */
9193 if (i >= nbgroups) {
9194 break;
9195 }
9196 if (lasts[i] != NULL) {
9197 lasts[i]->next = cur;
9198 lasts[i] = cur;
9199 } else {
9200 list[i] = cur;
9201 lasts[i] = cur;
9202 }
9203 if (cur->next != NULL)
9204 lastchg = cur->next;
9205 else
9206 lastchg = cur;
9207 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009208 }
9209 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009210 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9211 ret = -1;
9212 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009213 }
9214 lastelem = cur;
9215 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009216 for (i = 0; i < nbgroups; i++) {
9217 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9218 group = partitions->groups[i];
9219 if (lasts[i] != NULL) {
9220 last = lasts[i]->next;
9221 lasts[i]->next = NULL;
9222 }
9223 ctxt->state->seq = list[i];
9224 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9225 if (ret != 0)
9226 break;
9227 if (ctxt->state != NULL) {
9228 cur = ctxt->state->seq;
9229 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9230 xmlRelaxNGFreeValidState(ctxt, oldstate);
9231 oldstate = ctxt->state;
9232 ctxt->state = NULL;
9233 if (cur != NULL) {
9234 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9235 ret = -1;
9236 ctxt->state = oldstate;
9237 goto done;
9238 }
9239 } else if (ctxt->states != NULL) {
9240 int j;
9241 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009242
Daniel Veillard4c004142003-10-07 11:33:24 +00009243 for (j = 0; j < ctxt->states->nbState; j++) {
9244 cur = ctxt->states->tabState[j]->seq;
9245 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9246 if (cur == NULL) {
9247 found = 1;
9248 break;
9249 }
9250 }
9251 if (ctxt->states->nbState > 0) {
9252 xmlRelaxNGFreeValidState(ctxt, oldstate);
9253 oldstate =
9254 ctxt->states->tabState[ctxt->states->nbState - 1];
9255 }
9256 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9257 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9258 }
9259 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9260 ctxt->states = NULL;
9261 if (found == 0) {
9262 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9263 ret = -1;
9264 ctxt->state = oldstate;
9265 goto done;
9266 }
9267 } else {
9268 ret = -1;
9269 break;
9270 }
9271 if (lasts[i] != NULL) {
9272 lasts[i]->next = last;
9273 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009274 }
9275 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009276 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009277 ctxt->state = oldstate;
9278 ctxt->state->seq = lastelem;
9279 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009280 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9281 ret = -1;
9282 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009283 }
9284
Daniel Veillard4c004142003-10-07 11:33:24 +00009285 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009286 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009287 /*
9288 * builds the next links chain from the prev one
9289 */
9290 cur = lastchg;
9291 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009292 if ((cur == start) || (cur->prev == NULL))
9293 break;
9294 cur->prev->next = cur;
9295 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009296 }
9297 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009298 if (ctxt->errNr > errNr)
9299 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009300 }
9301
9302 xmlFree(list);
9303 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009304 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009305}
9306
9307/**
9308 * xmlRelaxNGValidateDefinitionList:
9309 * @ctxt: a Relax-NG validation context
9310 * @define: the list of definition to verify
9311 *
9312 * Validate the given node content against the (list) of definitions
9313 *
9314 * Returns 0 if the validation succeeded or an error code.
9315 */
9316static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009317xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9318 xmlRelaxNGDefinePtr defines)
9319{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009320 int ret = 0, res;
9321
9322
Daniel Veillard952379b2003-03-17 15:37:12 +00009323 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009324 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9325 BAD_CAST "NULL definition list");
9326 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009327 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009328 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009329 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9330 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9331 if (res < 0)
9332 ret = -1;
9333 } else {
9334 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9335 return (-1);
9336 }
9337 if (res == -1) /* continues on -2 */
9338 break;
9339 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009340 }
9341
Daniel Veillard4c004142003-10-07 11:33:24 +00009342 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009343}
9344
9345/**
9346 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009347 * @ctxt: a Relax-NG validation context
9348 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009349 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009350 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009351 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009352 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009353 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009354 */
9355static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009356xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9357 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9358{
Daniel Veillard580ced82003-03-21 21:22:48 +00009359 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009360
Daniel Veillardfd573f12003-03-16 17:52:32 +00009361 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009362 if (!xmlStrEqual(elem->name, define->name)) {
9363 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9364 return (0);
9365 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009366 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009367 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009368 if (elem->ns == NULL) {
9369 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9370 return (0);
9371 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9372 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9373 elem->name, define->ns);
9374 return (0);
9375 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009376 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009377 (define->name == NULL)) {
9378 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9379 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009380 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009381 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9382 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009383 }
9384
9385 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009386 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009387
9388 define = define->nameClass;
9389 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009390 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009391
Daniel Veillard4c004142003-10-07 11:33:24 +00009392 if (ctxt != NULL) {
9393 oldflags = ctxt->flags;
9394 ctxt->flags |= FLAGS_IGNORABLE;
9395 }
9396
9397 list = define->content;
9398 while (list != NULL) {
9399 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9400 if (ret == 1) {
9401 if (ctxt != NULL)
9402 ctxt->flags = oldflags;
9403 return (0);
9404 }
9405 if (ret < 0) {
9406 if (ctxt != NULL)
9407 ctxt->flags = oldflags;
9408 return (ret);
9409 }
9410 list = list->next;
9411 }
9412 ret = 1;
9413 if (ctxt != NULL) {
9414 ctxt->flags = oldflags;
9415 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009416 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009417 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009418
Daniel Veillard4c004142003-10-07 11:33:24 +00009419 if (ctxt != NULL) {
9420 oldflags = ctxt->flags;
9421 ctxt->flags |= FLAGS_IGNORABLE;
9422 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009423
Daniel Veillard4c004142003-10-07 11:33:24 +00009424 list = define->nameClass;
9425 while (list != NULL) {
9426 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9427 if (ret == 1) {
9428 if (ctxt != NULL)
9429 ctxt->flags = oldflags;
9430 return (1);
9431 }
9432 if (ret < 0) {
9433 if (ctxt != NULL)
9434 ctxt->flags = oldflags;
9435 return (ret);
9436 }
9437 list = list->next;
9438 }
9439 if (ctxt != NULL) {
9440 if (ret != 0) {
9441 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9442 xmlRelaxNGDumpValidError(ctxt);
9443 } else {
9444 if (ctxt->errNr > 0)
9445 xmlRelaxNGPopErrors(ctxt, 0);
9446 }
9447 }
9448 ret = 0;
9449 if (ctxt != NULL) {
9450 ctxt->flags = oldflags;
9451 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009452 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009453 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009454 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009455 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009456}
9457
9458/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009459 * xmlRelaxNGBestState:
9460 * @ctxt: a Relax-NG validation context
9461 *
9462 * Find the "best" state in the ctxt->states list of states to report
9463 * errors about. I.e. a state with no element left in the child list
9464 * or the one with the less attributes left.
9465 * This is called only if a falidation error was detected
9466 *
9467 * Returns the index of the "best" state or -1 in case of error
9468 */
9469static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009470xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9471{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009472 xmlRelaxNGValidStatePtr state;
9473 int i, tmp;
9474 int best = -1;
9475 int value = 1000000;
9476
9477 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9478 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009479 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009480
Daniel Veillard4c004142003-10-07 11:33:24 +00009481 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009482 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009483 if (state == NULL)
9484 continue;
9485 if (state->seq != NULL) {
9486 if ((best == -1) || (value > 100000)) {
9487 value = 100000;
9488 best = i;
9489 }
9490 } else {
9491 tmp = state->nbAttrLeft;
9492 if ((best == -1) || (value > tmp)) {
9493 value = tmp;
9494 best = i;
9495 }
9496 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009497 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009498 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009499}
9500
9501/**
9502 * xmlRelaxNGLogBestError:
9503 * @ctxt: a Relax-NG validation context
9504 *
9505 * Find the "best" state in the ctxt->states list of states to report
9506 * errors about and log it.
9507 */
9508static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009509xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9510{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009511 int best;
9512
9513 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9514 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009515 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009516
9517 best = xmlRelaxNGBestState(ctxt);
9518 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009519 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009520
Daniel Veillard4c004142003-10-07 11:33:24 +00009521 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009522 }
9523}
9524
9525/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009526 * xmlRelaxNGValidateElementEnd:
9527 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009528 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009529 *
9530 * Validate the end of the element, implements check that
9531 * there is nothing left not consumed in the element content
9532 * or in the attribute list.
9533 *
9534 * Returns 0 if the validation succeeded or an error code.
9535 */
9536static int
William M. Brack272693c2003-11-14 16:20:34 +00009537xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009538{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009539 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009540 xmlRelaxNGValidStatePtr state;
9541
9542 state = ctxt->state;
9543 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009544 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9545 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009546 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009547 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9548 state->node->name, state->seq->name);
9549 }
9550 return (-1);
9551 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009552 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009553 for (i = 0; i < state->nbAttrs; i++) {
9554 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009555 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009556 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9557 state->attrs[i]->name, state->node->name);
9558 }
9559 return (-1 - i);
9560 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009561 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009562 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009563}
9564
9565/**
9566 * xmlRelaxNGValidateState:
9567 * @ctxt: a Relax-NG validation context
9568 * @define: the definition to verify
9569 *
9570 * Validate the current state against the definition
9571 *
9572 * Returns 0 if the validation succeeded or an error code.
9573 */
9574static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009575xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9576 xmlRelaxNGDefinePtr define)
9577{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009578 xmlNodePtr node;
9579 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009580 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009581
9582 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009583 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9584 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009585 }
9586
9587 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009588 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009589 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009590 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009591 }
9592#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009593 for (i = 0; i < ctxt->depth; i++)
9594 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009596 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009597 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009598 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009599 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009600 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009601 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009602 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009603#endif
9604 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009605 switch (define->type) {
9606 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009607 node = xmlRelaxNGSkipIgnored(ctxt, node);
9608 ret = 0;
9609 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009610 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009611 ret = -1;
9612 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009613 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009614 while ((node != NULL) &&
9615 ((node->type == XML_TEXT_NODE) ||
9616 (node->type == XML_COMMENT_NODE) ||
9617 (node->type == XML_PI_NODE) ||
9618 (node->type == XML_CDATA_SECTION_NODE)))
9619 node = node->next;
9620 ctxt->state->seq = node;
9621 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009622 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009623 errNr = ctxt->errNr;
9624 node = xmlRelaxNGSkipIgnored(ctxt, node);
9625 if (node == NULL) {
9626 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9627 ret = -1;
9628 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9629 xmlRelaxNGDumpValidError(ctxt);
9630 break;
9631 }
9632 if (node->type != XML_ELEMENT_NODE) {
9633 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9634 ret = -1;
9635 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9636 xmlRelaxNGDumpValidError(ctxt);
9637 break;
9638 }
9639 /*
9640 * This node was already validated successfully against
9641 * this definition.
9642 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009643 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009644 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9645 if (ctxt->errNr > errNr)
9646 xmlRelaxNGPopErrors(ctxt, errNr);
9647 if (ctxt->errNr != 0) {
9648 while ((ctxt->err != NULL) &&
9649 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9650 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9651 ||
9652 ((ctxt->err->err ==
9653 XML_RELAXNG_ERR_ELEMEXTRANS)
9654 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9655 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9656 || (ctxt->err->err ==
9657 XML_RELAXNG_ERR_NOTELEM)))
9658 xmlRelaxNGValidErrorPop(ctxt);
9659 }
9660 break;
9661 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009662
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009663 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9664 if (ret <= 0) {
9665 ret = -1;
9666 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9667 xmlRelaxNGDumpValidError(ctxt);
9668 break;
9669 }
9670 ret = 0;
9671 if (ctxt->errNr != 0) {
9672 if (ctxt->errNr > errNr)
9673 xmlRelaxNGPopErrors(ctxt, errNr);
9674 while ((ctxt->err != NULL) &&
9675 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9676 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9677 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9678 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9679 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9680 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9681 xmlRelaxNGValidErrorPop(ctxt);
9682 }
9683 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009684
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009685 oldflags = ctxt->flags;
9686 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9687 ctxt->flags -= FLAGS_MIXED_CONTENT;
9688 }
9689 state = xmlRelaxNGNewValidState(ctxt, node);
9690 if (state == NULL) {
9691 ret = -1;
9692 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9693 xmlRelaxNGDumpValidError(ctxt);
9694 break;
9695 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009696
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009697 oldstate = ctxt->state;
9698 ctxt->state = state;
9699 if (define->attrs != NULL) {
9700 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9701 if (tmp != 0) {
9702 ret = -1;
9703 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9704 }
9705 }
9706 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009707 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9708 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9709 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009710
Daniel Veillard4c004142003-10-07 11:33:24 +00009711 nstate = xmlRelaxNGNewValidState(ctxt, node);
9712 ctxt->state = nstate;
9713 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009714
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009715 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9716 define->contModel,
9717 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009718 nseq = ctxt->state->seq;
9719 ctxt->state = tmpstate;
9720 ctxt->states = tmpstates;
9721 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009722
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009723#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009724 xmlGenericError(xmlGenericErrorContext,
9725 "Validating content of '%s' : %d\n",
9726 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009727#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009728 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009729 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009730
9731 if (ctxt->states != NULL) {
9732 tmp = -1;
9733
Daniel Veillardce192eb2003-04-16 15:58:05 +00009734 for (i = 0; i < ctxt->states->nbState; i++) {
9735 state = ctxt->states->tabState[i];
9736 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009737 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009738
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009739 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009740 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009741 break;
9742 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009743 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009744 if (tmp != 0) {
9745 /*
9746 * validation error, log the message for the "best" one
9747 */
9748 ctxt->flags |= FLAGS_IGNORABLE;
9749 xmlRelaxNGLogBestError(ctxt);
9750 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009751 for (i = 0; i < ctxt->states->nbState; i++) {
9752 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009753 ctxt->states->
9754 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009755 }
9756 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9757 ctxt->flags = oldflags;
9758 ctxt->states = NULL;
9759 if ((ret == 0) && (tmp == -1))
9760 ret = -1;
9761 } else {
9762 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009763 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009764 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009765 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009766 xmlRelaxNGFreeValidState(ctxt, state);
9767 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009768 } else {
9769 if (define->content != NULL) {
9770 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009771 define->
9772 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009773 if (tmp != 0) {
9774 ret = -1;
9775 if (ctxt->state == NULL) {
9776 ctxt->state = oldstate;
9777 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9778 node->name);
9779 ctxt->state = NULL;
9780 } else {
9781 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9782 node->name);
9783 }
9784
9785 }
9786 }
9787 if (ctxt->states != NULL) {
9788 tmp = -1;
9789
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009790 for (i = 0; i < ctxt->states->nbState; i++) {
9791 state = ctxt->states->tabState[i];
9792 ctxt->state = state;
9793
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009794 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009795 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009796 break;
9797 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009798 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009799 if (tmp != 0) {
9800 /*
9801 * validation error, log the message for the "best" one
9802 */
9803 ctxt->flags |= FLAGS_IGNORABLE;
9804 xmlRelaxNGLogBestError(ctxt);
9805 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009806 for (i = 0; i < ctxt->states->nbState; i++) {
9807 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009808 ctxt->states->
9809 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009810 }
9811 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9812 ctxt->flags = oldflags;
9813 ctxt->states = NULL;
9814 if ((ret == 0) && (tmp == -1))
9815 ret = -1;
9816 } else {
9817 state = ctxt->state;
9818 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009819 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009820 xmlRelaxNGFreeValidState(ctxt, state);
9821 }
9822 }
9823 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009824 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009825 }
9826 ctxt->flags = oldflags;
9827 ctxt->state = oldstate;
9828 if (oldstate != NULL)
9829 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9830 if (ret != 0) {
9831 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9832 xmlRelaxNGDumpValidError(ctxt);
9833 ret = 0;
9834 } else {
9835 ret = -2;
9836 }
9837 } else {
9838 if (ctxt->errNr > errNr)
9839 xmlRelaxNGPopErrors(ctxt, errNr);
9840 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009841
9842#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009843 xmlGenericError(xmlGenericErrorContext,
9844 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9845 node->name, ret);
9846 if (oldstate == NULL)
9847 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9848 else if (oldstate->seq == NULL)
9849 xmlGenericError(xmlGenericErrorContext, ": done\n");
9850 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9851 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9852 oldstate->seq->name);
9853 else
9854 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9855 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009856#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009857 break;
9858 case XML_RELAXNG_OPTIONAL:{
9859 errNr = ctxt->errNr;
9860 oldflags = ctxt->flags;
9861 ctxt->flags |= FLAGS_IGNORABLE;
9862 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9863 ret =
9864 xmlRelaxNGValidateDefinitionList(ctxt,
9865 define->content);
9866 if (ret != 0) {
9867 if (ctxt->state != NULL)
9868 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9869 ctxt->state = oldstate;
9870 ctxt->flags = oldflags;
9871 ret = 0;
9872 if (ctxt->errNr > errNr)
9873 xmlRelaxNGPopErrors(ctxt, errNr);
9874 break;
9875 }
9876 if (ctxt->states != NULL) {
9877 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9878 } else {
9879 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9880 if (ctxt->states == NULL) {
9881 xmlRelaxNGFreeValidState(ctxt, oldstate);
9882 ctxt->flags = oldflags;
9883 ret = -1;
9884 if (ctxt->errNr > errNr)
9885 xmlRelaxNGPopErrors(ctxt, errNr);
9886 break;
9887 }
9888 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9889 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9890 ctxt->state = NULL;
9891 }
9892 ctxt->flags = oldflags;
9893 ret = 0;
9894 if (ctxt->errNr > errNr)
9895 xmlRelaxNGPopErrors(ctxt, errNr);
9896 break;
9897 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009898 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009899 errNr = ctxt->errNr;
9900 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9901 if (ret != 0) {
9902 break;
9903 }
9904 if (ctxt->errNr > errNr)
9905 xmlRelaxNGPopErrors(ctxt, errNr);
9906 /* no break on purpose */
9907 case XML_RELAXNG_ZEROORMORE:{
9908 int progress;
9909 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9910 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009911
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009912 errNr = ctxt->errNr;
9913 res = xmlRelaxNGNewStates(ctxt, 1);
9914 if (res == NULL) {
9915 ret = -1;
9916 break;
9917 }
9918 /*
9919 * All the input states are also exit states
9920 */
9921 if (ctxt->state != NULL) {
9922 xmlRelaxNGAddStates(ctxt, res,
9923 xmlRelaxNGCopyValidState(ctxt,
9924 ctxt->
9925 state));
9926 } else {
9927 for (j = 0; j < ctxt->states->nbState; j++) {
9928 xmlRelaxNGAddStates(ctxt, res,
9929 xmlRelaxNGCopyValidState(ctxt,
9930 ctxt->
9931 states->
9932 tabState
9933 [j]));
9934 }
9935 }
9936 oldflags = ctxt->flags;
9937 ctxt->flags |= FLAGS_IGNORABLE;
9938 do {
9939 progress = 0;
9940 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009941
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009942 if (ctxt->states != NULL) {
9943 states = ctxt->states;
9944 for (i = 0; i < states->nbState; i++) {
9945 ctxt->state = states->tabState[i];
9946 ctxt->states = NULL;
9947 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9948 define->
9949 content);
9950 if (ret == 0) {
9951 if (ctxt->state != NULL) {
9952 tmp = xmlRelaxNGAddStates(ctxt, res,
9953 ctxt->state);
9954 ctxt->state = NULL;
9955 if (tmp == 1)
9956 progress = 1;
9957 } else if (ctxt->states != NULL) {
9958 for (j = 0; j < ctxt->states->nbState;
9959 j++) {
9960 tmp =
9961 xmlRelaxNGAddStates(ctxt, res,
9962 ctxt->
9963 states->
9964 tabState
9965 [j]);
9966 if (tmp == 1)
9967 progress = 1;
9968 }
9969 xmlRelaxNGFreeStates(ctxt,
9970 ctxt->states);
9971 ctxt->states = NULL;
9972 }
9973 } else {
9974 if (ctxt->state != NULL) {
9975 xmlRelaxNGFreeValidState(ctxt,
9976 ctxt->state);
9977 ctxt->state = NULL;
9978 }
9979 }
9980 }
9981 } else {
9982 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9983 define->
9984 content);
9985 if (ret != 0) {
9986 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9987 ctxt->state = NULL;
9988 } else {
9989 base = res->nbState;
9990 if (ctxt->state != NULL) {
9991 tmp = xmlRelaxNGAddStates(ctxt, res,
9992 ctxt->state);
9993 ctxt->state = NULL;
9994 if (tmp == 1)
9995 progress = 1;
9996 } else if (ctxt->states != NULL) {
9997 for (j = 0; j < ctxt->states->nbState; j++) {
9998 tmp = xmlRelaxNGAddStates(ctxt, res,
9999 ctxt->
10000 states->
10001 tabState[j]);
10002 if (tmp == 1)
10003 progress = 1;
10004 }
10005 if (states == NULL) {
10006 states = ctxt->states;
10007 } else {
10008 xmlRelaxNGFreeStates(ctxt,
10009 ctxt->states);
10010 }
10011 ctxt->states = NULL;
10012 }
10013 }
10014 }
10015 if (progress) {
10016 /*
10017 * Collect all the new nodes added at that step
10018 * and make them the new node set
10019 */
10020 if (res->nbState - base == 1) {
10021 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10022 res->
10023 tabState
10024 [base]);
10025 } else {
10026 if (states == NULL) {
10027 xmlRelaxNGNewStates(ctxt,
10028 res->nbState - base);
10029 }
10030 states->nbState = 0;
10031 for (i = base; i < res->nbState; i++)
10032 xmlRelaxNGAddStates(ctxt, states,
10033 xmlRelaxNGCopyValidState
10034 (ctxt,
10035 res->tabState[i]));
10036 ctxt->states = states;
10037 }
10038 }
10039 } while (progress == 1);
10040 if (states != NULL) {
10041 xmlRelaxNGFreeStates(ctxt, states);
10042 }
10043 ctxt->states = res;
10044 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010045#if 0
10046 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010047 * errors may have to be propagated back...
10048 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010049 if (ctxt->errNr > errNr)
10050 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010051#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010052 ret = 0;
10053 break;
10054 }
10055 case XML_RELAXNG_CHOICE:{
10056 xmlRelaxNGDefinePtr list = NULL;
10057 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010058
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010059 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010060
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010061 errNr = ctxt->errNr;
Daniel Veillard9186a1f2005-01-15 12:38:10 +000010062 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10063 (node != NULL)) {
10064 /*
10065 * node == NULL can't be optimized since IS_TRIABLE
10066 * doesn't account for choice which may lead to
10067 * only attributes.
10068 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010069 xmlHashTablePtr triage =
10070 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010071
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010072 /*
10073 * Something we can optimize cleanly there is only one
10074 * possble branch out !
10075 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010076 if ((node->type == XML_TEXT_NODE) ||
10077 (node->type == XML_CDATA_SECTION_NODE)) {
10078 list =
10079 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10080 } else if (node->type == XML_ELEMENT_NODE) {
10081 if (node->ns != NULL) {
10082 list = xmlHashLookup2(triage, node->name,
10083 node->ns->href);
10084 if (list == NULL)
10085 list =
10086 xmlHashLookup2(triage, BAD_CAST "#any",
10087 node->ns->href);
10088 } else
10089 list =
10090 xmlHashLookup2(triage, node->name, NULL);
10091 if (list == NULL)
10092 list =
10093 xmlHashLookup2(triage, BAD_CAST "#any",
10094 NULL);
10095 }
10096 if (list == NULL) {
10097 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010098 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010099 break;
10100 }
10101 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10102 if (ret == 0) {
10103 }
10104 break;
10105 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010106
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010107 list = define->content;
10108 oldflags = ctxt->flags;
10109 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010110
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010111 while (list != NULL) {
10112 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10113 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10114 if (ret == 0) {
10115 if (states == NULL) {
10116 states = xmlRelaxNGNewStates(ctxt, 1);
10117 }
10118 if (ctxt->state != NULL) {
10119 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10120 } else if (ctxt->states != NULL) {
10121 for (i = 0; i < ctxt->states->nbState; i++) {
10122 xmlRelaxNGAddStates(ctxt, states,
10123 ctxt->states->
10124 tabState[i]);
10125 }
10126 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10127 ctxt->states = NULL;
10128 }
10129 } else {
10130 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10131 }
10132 ctxt->state = oldstate;
10133 list = list->next;
10134 }
10135 if (states != NULL) {
10136 xmlRelaxNGFreeValidState(ctxt, oldstate);
10137 ctxt->states = states;
10138 ctxt->state = NULL;
10139 ret = 0;
10140 } else {
10141 ctxt->states = NULL;
10142 }
10143 ctxt->flags = oldflags;
10144 if (ret != 0) {
10145 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10146 xmlRelaxNGDumpValidError(ctxt);
10147 }
10148 } else {
10149 if (ctxt->errNr > errNr)
10150 xmlRelaxNGPopErrors(ctxt, errNr);
10151 }
10152 break;
10153 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010154 case XML_RELAXNG_DEF:
10155 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010156 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10157 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010158 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010159 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10160 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010161 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010162 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10163 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010164 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010165 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010166 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010167 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010168 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010169 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10170 break;
10171 case XML_RELAXNG_DATATYPE:{
10172 xmlNodePtr child;
10173 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010174
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010175 child = node;
10176 while (child != NULL) {
10177 if (child->type == XML_ELEMENT_NODE) {
10178 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10179 node->parent->name);
10180 ret = -1;
10181 break;
10182 } else if ((child->type == XML_TEXT_NODE) ||
10183 (child->type == XML_CDATA_SECTION_NODE)) {
10184 content = xmlStrcat(content, child->content);
10185 }
10186 /* TODO: handle entities ... */
10187 child = child->next;
10188 }
10189 if (ret == -1) {
10190 if (content != NULL)
10191 xmlFree(content);
10192 break;
10193 }
10194 if (content == NULL) {
10195 content = xmlStrdup(BAD_CAST "");
10196 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010197 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010198 ret = -1;
10199 break;
10200 }
10201 }
10202 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10203 ctxt->state->seq);
10204 if (ret == -1) {
10205 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10206 } else if (ret == 0) {
10207 ctxt->state->seq = NULL;
10208 }
10209 if (content != NULL)
10210 xmlFree(content);
10211 break;
10212 }
10213 case XML_RELAXNG_VALUE:{
10214 xmlChar *content = NULL;
10215 xmlChar *oldvalue;
10216 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010217
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010218 child = node;
10219 while (child != NULL) {
10220 if (child->type == XML_ELEMENT_NODE) {
10221 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10222 node->parent->name);
10223 ret = -1;
10224 break;
10225 } else if ((child->type == XML_TEXT_NODE) ||
10226 (child->type == XML_CDATA_SECTION_NODE)) {
10227 content = xmlStrcat(content, child->content);
10228 }
10229 /* TODO: handle entities ... */
10230 child = child->next;
10231 }
10232 if (ret == -1) {
10233 if (content != NULL)
10234 xmlFree(content);
10235 break;
10236 }
10237 if (content == NULL) {
10238 content = xmlStrdup(BAD_CAST "");
10239 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010240 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010241 ret = -1;
10242 break;
10243 }
10244 }
10245 oldvalue = ctxt->state->value;
10246 ctxt->state->value = content;
10247 ret = xmlRelaxNGValidateValue(ctxt, define);
10248 ctxt->state->value = oldvalue;
10249 if (ret == -1) {
10250 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10251 } else if (ret == 0) {
10252 ctxt->state->seq = NULL;
10253 }
10254 if (content != NULL)
10255 xmlFree(content);
10256 break;
10257 }
10258 case XML_RELAXNG_LIST:{
10259 xmlChar *content;
10260 xmlNodePtr child;
10261 xmlChar *oldvalue, *oldendvalue;
10262 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010263
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010264 /*
10265 * Make sure it's only text nodes
10266 */
10267
10268 content = NULL;
10269 child = node;
10270 while (child != NULL) {
10271 if (child->type == XML_ELEMENT_NODE) {
10272 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10273 node->parent->name);
10274 ret = -1;
10275 break;
10276 } else if ((child->type == XML_TEXT_NODE) ||
10277 (child->type == XML_CDATA_SECTION_NODE)) {
10278 content = xmlStrcat(content, child->content);
10279 }
10280 /* TODO: handle entities ... */
10281 child = child->next;
10282 }
10283 if (ret == -1) {
10284 if (content != NULL)
10285 xmlFree(content);
10286 break;
10287 }
10288 if (content == NULL) {
10289 content = xmlStrdup(BAD_CAST "");
10290 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010291 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010292 ret = -1;
10293 break;
10294 }
10295 }
10296 len = xmlStrlen(content);
10297 oldvalue = ctxt->state->value;
10298 oldendvalue = ctxt->state->endvalue;
10299 ctxt->state->value = content;
10300 ctxt->state->endvalue = content + len;
10301 ret = xmlRelaxNGValidateValue(ctxt, define);
10302 ctxt->state->value = oldvalue;
10303 ctxt->state->endvalue = oldendvalue;
10304 if (ret == -1) {
10305 VALID_ERR(XML_RELAXNG_ERR_LIST);
10306 } else if ((ret == 0) && (node != NULL)) {
10307 ctxt->state->seq = node->next;
10308 }
10309 if (content != NULL)
10310 xmlFree(content);
10311 break;
10312 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010313 case XML_RELAXNG_EXCEPT:
10314 case XML_RELAXNG_PARAM:
10315 TODO ret = -1;
10316 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010317 }
10318 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010319#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010320 for (i = 0; i < ctxt->depth; i++)
10321 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010322 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010323 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010324 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010325 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010326 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010327 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010328 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010329 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010330#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010331 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010332}
10333
10334/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010335 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010336 * @ctxt: a Relax-NG validation context
10337 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010338 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010339 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010340 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010341 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010342 */
10343static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010344xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10345 xmlRelaxNGDefinePtr define)
10346{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010347 xmlRelaxNGStatesPtr states, res;
10348 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010349
Daniel Veillardfd573f12003-03-16 17:52:32 +000010350 /*
10351 * We should NOT have both ctxt->state and ctxt->states
10352 */
10353 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010354 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10355 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010356 }
10357
10358 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010359 if (ctxt->states != NULL) {
10360 ctxt->state = ctxt->states->tabState[0];
10361 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10362 ctxt->states = NULL;
10363 }
10364 ret = xmlRelaxNGValidateState(ctxt, define);
10365 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10366 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10367 ctxt->state = NULL;
10368 }
10369 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10370 ctxt->state = ctxt->states->tabState[0];
10371 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10372 ctxt->states = NULL;
10373 }
10374 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010375 }
10376
10377 states = ctxt->states;
10378 ctxt->states = NULL;
10379 res = NULL;
10380 j = 0;
10381 oldflags = ctxt->flags;
10382 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010383 for (i = 0; i < states->nbState; i++) {
10384 ctxt->state = states->tabState[i];
10385 ctxt->states = NULL;
10386 ret = xmlRelaxNGValidateState(ctxt, define);
10387 /*
10388 * We should NOT have both ctxt->state and ctxt->states
10389 */
10390 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10391 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10392 ctxt->state = NULL;
10393 }
10394 if (ret == 0) {
10395 if (ctxt->states == NULL) {
10396 if (res != NULL) {
10397 /* add the state to the container */
10398 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10399 ctxt->state = NULL;
10400 } else {
10401 /* add the state directly in states */
10402 states->tabState[j++] = ctxt->state;
10403 ctxt->state = NULL;
10404 }
10405 } else {
10406 if (res == NULL) {
10407 /* make it the new container and copy other results */
10408 res = ctxt->states;
10409 ctxt->states = NULL;
10410 for (k = 0; k < j; k++)
10411 xmlRelaxNGAddStates(ctxt, res,
10412 states->tabState[k]);
10413 } else {
10414 /* add all the new results to res and reff the container */
10415 for (k = 0; k < ctxt->states->nbState; k++)
10416 xmlRelaxNGAddStates(ctxt, res,
10417 ctxt->states->tabState[k]);
10418 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10419 ctxt->states = NULL;
10420 }
10421 }
10422 } else {
10423 if (ctxt->state != NULL) {
10424 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10425 ctxt->state = NULL;
10426 } else if (ctxt->states != NULL) {
10427 for (k = 0; k < ctxt->states->nbState; k++)
10428 xmlRelaxNGFreeValidState(ctxt,
10429 ctxt->states->tabState[k]);
10430 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10431 ctxt->states = NULL;
10432 }
10433 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010434 }
10435 ctxt->flags = oldflags;
10436 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010437 xmlRelaxNGFreeStates(ctxt, states);
10438 ctxt->states = res;
10439 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010440 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010441 states->nbState = j;
10442 ctxt->states = states;
10443 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010444 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010445 ctxt->state = states->tabState[0];
10446 xmlRelaxNGFreeStates(ctxt, states);
10447 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010448 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010449 ret = -1;
10450 xmlRelaxNGFreeStates(ctxt, states);
10451 if (ctxt->states != NULL) {
10452 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10453 ctxt->states = NULL;
10454 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010455 }
10456 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010457 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10458 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010459 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010460 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010461}
10462
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010463/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010464 * xmlRelaxNGValidateDocument:
10465 * @ctxt: a Relax-NG validation context
10466 * @doc: the document
10467 *
10468 * Validate the given document
10469 *
10470 * Returns 0 if the validation succeeded or an error code.
10471 */
10472static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010473xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10474{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010475 int ret;
10476 xmlRelaxNGPtr schema;
10477 xmlRelaxNGGrammarPtr grammar;
10478 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010479 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010480
10481 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010482 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010483
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010484 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010485 schema = ctxt->schema;
10486 grammar = schema->topgrammar;
10487 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010488 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10489 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010490 }
10491 state = xmlRelaxNGNewValidState(ctxt, NULL);
10492 ctxt->state = state;
10493 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010494 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010495 state = ctxt->state;
10496 node = state->seq;
10497 node = xmlRelaxNGSkipIgnored(ctxt, node);
10498 if (node != NULL) {
10499 if (ret != -1) {
10500 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10501 ret = -1;
10502 }
10503 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010504 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010505 int i;
10506 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010507
Daniel Veillard4c004142003-10-07 11:33:24 +000010508 for (i = 0; i < ctxt->states->nbState; i++) {
10509 state = ctxt->states->tabState[i];
10510 node = state->seq;
10511 node = xmlRelaxNGSkipIgnored(ctxt, node);
10512 if (node == NULL)
10513 tmp = 0;
10514 xmlRelaxNGFreeValidState(ctxt, state);
10515 }
10516 if (tmp == -1) {
10517 if (ret != -1) {
10518 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10519 ret = -1;
10520 }
10521 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010522 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010523 if (ctxt->state != NULL) {
10524 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010525 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010526 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010527 if (ret != 0)
10528 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010529#ifdef DEBUG
10530 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010531 ctxt->error(ctxt->userData,
10532 "%d Extra error messages left on stack !\n",
10533 ctxt->errNr);
10534 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010535 }
10536#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010537#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010538 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010539 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010540
Daniel Veillard4c004142003-10-07 11:33:24 +000010541 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10542 vctxt.valid = 1;
10543 vctxt.error = ctxt->error;
10544 vctxt.warning = ctxt->warning;
10545 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010546
Daniel Veillard4c004142003-10-07 11:33:24 +000010547 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10548 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010549 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010550#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010551 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010552 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010553
Daniel Veillard4c004142003-10-07 11:33:24 +000010554 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010555}
10556
Daniel Veillardfd573f12003-03-16 17:52:32 +000010557/************************************************************************
10558 * *
10559 * Validation interfaces *
10560 * *
10561 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010562
Daniel Veillard6eadf632003-01-23 18:29:16 +000010563/**
10564 * xmlRelaxNGNewValidCtxt:
10565 * @schema: a precompiled XML RelaxNGs
10566 *
10567 * Create an XML RelaxNGs validation context based on the given schema
10568 *
10569 * Returns the validation context or NULL in case of error
10570 */
10571xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010572xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10573{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010574 xmlRelaxNGValidCtxtPtr ret;
10575
10576 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10577 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010578 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010579 return (NULL);
10580 }
10581 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10582 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010583 ret->error = xmlGenericError;
10584 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010585 ret->errNr = 0;
10586 ret->errMax = 0;
10587 ret->err = NULL;
10588 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010589 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010590 ret->states = NULL;
10591 ret->freeState = NULL;
10592 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010593 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010594 return (ret);
10595}
10596
10597/**
10598 * xmlRelaxNGFreeValidCtxt:
10599 * @ctxt: the schema validation context
10600 *
10601 * Free the resources associated to the schema validation context
10602 */
10603void
Daniel Veillard4c004142003-10-07 11:33:24 +000010604xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10605{
Daniel Veillard798024a2003-03-19 10:36:09 +000010606 int k;
10607
Daniel Veillard6eadf632003-01-23 18:29:16 +000010608 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010609 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010610 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010611 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010612 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010613 for (k = 0; k < ctxt->freeState->nbState; k++) {
10614 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10615 }
10616 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010617 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010618 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010619 for (k = 0; k < ctxt->freeStatesNr; k++) {
10620 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10621 }
10622 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010623 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010624 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010625 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010626 if (ctxt->elemTab != NULL) {
10627 xmlRegExecCtxtPtr exec;
10628
Daniel Veillard4c004142003-10-07 11:33:24 +000010629 exec = xmlRelaxNGElemPop(ctxt);
10630 while (exec != NULL) {
10631 xmlRegFreeExecCtxt(exec);
10632 exec = xmlRelaxNGElemPop(ctxt);
10633 }
10634 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010635 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010636 xmlFree(ctxt);
10637}
10638
10639/**
10640 * xmlRelaxNGSetValidErrors:
10641 * @ctxt: a Relax-NG validation context
10642 * @err: the error function
10643 * @warn: the warning function
10644 * @ctx: the functions context
10645 *
10646 * Set the error and warning callback informations
10647 */
10648void
10649xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010650 xmlRelaxNGValidityErrorFunc err,
10651 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10652{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010653 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010654 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010655 ctxt->error = err;
10656 ctxt->warning = warn;
10657 ctxt->userData = ctx;
10658}
10659
10660/**
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010661 * xmlRelaxNGSetValidStructuredErrors:
10662 * @ctxt: a Relax-NG validation context
10663 * @serror: the structured error function
10664 * @ctx: the functions context
10665 *
10666 * Set the structured error callback
10667 */
10668void
10669xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
10670 xmlStructuredErrorFunc serror, void *ctx)
10671{
10672 if (ctxt == NULL)
10673 return;
10674 ctxt->serror = serror;
10675 ctxt->error = NULL;
10676 ctxt->warning = NULL;
10677 ctxt->userData = ctx;
10678}
10679
10680/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010681 * xmlRelaxNGGetValidErrors:
10682 * @ctxt: a Relax-NG validation context
10683 * @err: the error function result
10684 * @warn: the warning function result
10685 * @ctx: the functions context result
10686 *
10687 * Get the error and warning callback informations
10688 *
10689 * Returns -1 in case of error and 0 otherwise
10690 */
10691int
10692xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010693 xmlRelaxNGValidityErrorFunc * err,
10694 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10695{
Daniel Veillard409a8142003-07-18 15:16:57 +000010696 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010697 return (-1);
10698 if (err != NULL)
10699 *err = ctxt->error;
10700 if (warn != NULL)
10701 *warn = ctxt->warning;
10702 if (ctx != NULL)
10703 *ctx = ctxt->userData;
10704 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010705}
10706
10707/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010708 * xmlRelaxNGValidateDoc:
10709 * @ctxt: a Relax-NG validation context
10710 * @doc: a parsed document tree
10711 *
10712 * Validate a document tree in memory.
10713 *
10714 * Returns 0 if the document is valid, a positive error code
10715 * number otherwise and -1 in case of internal or API error.
10716 */
10717int
Daniel Veillard4c004142003-10-07 11:33:24 +000010718xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10719{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010720 int ret;
10721
10722 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010723 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010724
10725 ctxt->doc = doc;
10726
10727 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010728 /*
10729 * TODO: build error codes
10730 */
10731 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010732 return (1);
10733 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010734}
10735
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010736#define bottom_relaxng
10737#include "elfgcchack.h"
Daniel Veillard6eadf632003-01-23 18:29:16 +000010738#endif /* LIBXML_SCHEMAS_ENABLED */