blob: 3cac364b9bbeddfad6e2e16571aab0d31d6b6aac [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 Veillard42f12e92003-03-07 18:32:59 +0000205 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000206
Daniel Veillard4c004142003-10-07 11:33:24 +0000207 xmlRelaxNGPtr schema; /* The schema in use */
208 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
209 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
210 int flags; /* parser flags */
211 int nbErrors; /* number of errors at parse time */
212 int nbWarnings; /* number of warnings at parse time */
213 const xmlChar *define; /* the current define scope */
214 xmlRelaxNGDefinePtr def; /* the current define */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000215
Daniel Veillard4c004142003-10-07 11:33:24 +0000216 int nbInterleaves;
217 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000218
Daniel Veillard4c004142003-10-07 11:33:24 +0000219 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
220 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
221 xmlChar *URL;
222 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000223
Daniel Veillard4c004142003-10-07 11:33:24 +0000224 int defNr; /* number of defines used */
225 int defMax; /* number of defines aloocated */
226 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard419a7682003-02-03 23:22:49 +0000227
Daniel Veillard4c004142003-10-07 11:33:24 +0000228 const char *buffer;
229 int size;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000230
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000231 /* the document stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000232 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
233 int docNr; /* Depth of the parsing stack */
234 int docMax; /* Max depth of the parsing stack */
235 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000236
237 /* the include stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000238 xmlRelaxNGIncludePtr inc; /* Current parsed include */
239 int incNr; /* Depth of the include parsing stack */
240 int incMax; /* Max depth of the parsing stack */
241 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000242
Daniel Veillard4c004142003-10-07 11:33:24 +0000243 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000244
245 /* used to compile content models */
Daniel Veillard4c004142003-10-07 11:33:24 +0000246 xmlAutomataPtr am; /* the automata */
247 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000248};
249
250#define FLAGS_IGNORABLE 1
251#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000252#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000253
254/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000255 * xmlRelaxNGInterleaveGroup:
256 *
257 * A RelaxNGs partition set associated to lists of definitions
258 */
259typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
260typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
261struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000262 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
263 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
264 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000265};
266
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000267#define IS_DETERMINIST 1
268#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000269
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000270/**
271 * xmlRelaxNGPartitions:
272 *
273 * A RelaxNGs partition associated to an interleave group
274 */
275typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
276typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
277struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000278 int nbgroups; /* number of groups in the partitions */
279 xmlHashTablePtr triage; /* hash table used to direct nodes to the
280 * right group when possible */
281 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000282 xmlRelaxNGInterleaveGroupPtr *groups;
283};
284
285/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000286 * xmlRelaxNGValidState:
287 *
288 * A RelaxNGs validation state
289 */
290#define MAX_ATTR 20
291typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
292typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
293struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000294 xmlNodePtr node; /* the current node */
295 xmlNodePtr seq; /* the sequence of children left to validate */
296 int nbAttrs; /* the number of attributes */
297 int maxAttrs; /* the size of attrs */
298 int nbAttrLeft; /* the number of attributes left to validate */
299 xmlChar *value; /* the value when operating on string */
300 xmlChar *endvalue; /* the end value when operating on string */
301 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000302};
303
304/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000305 * xmlRelaxNGStates:
306 *
307 * A RelaxNGs container for validation state
308 */
309typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
310typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
311struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000312 int nbState; /* the number of states */
313 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000314 xmlRelaxNGValidStatePtr *tabState;
315};
316
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000317#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000318
Daniel Veillardfd573f12003-03-16 17:52:32 +0000319/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000320 * xmlRelaxNGValidError:
321 *
322 * A RelaxNGs validation error
323 */
324typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
325typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
326struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000327 xmlRelaxNGValidErr err; /* the error number */
328 int flags; /* flags */
329 xmlNodePtr node; /* the current node */
330 xmlNodePtr seq; /* the current child */
331 const xmlChar *arg1; /* first arg */
332 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000333};
334
335/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000336 * xmlRelaxNGValidCtxt:
337 *
338 * A RelaxNGs validation context
339 */
340
341struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000342 void *userData; /* user specific data block */
343 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
344 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
345 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000346
Daniel Veillard4c004142003-10-07 11:33:24 +0000347 xmlRelaxNGPtr schema; /* The schema in use */
348 xmlDocPtr doc; /* the document being validated */
349 int flags; /* validation flags */
350 int depth; /* validation depth */
351 int idref; /* requires idref checking */
352 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000353
354 /*
355 * Errors accumulated in branches may have to be stacked to be
356 * provided back when it's sure they affect validation.
357 */
358 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000359 int errNr; /* Depth of the error stack */
360 int errMax; /* Max depth of the error stack */
361 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000362
Daniel Veillard4c004142003-10-07 11:33:24 +0000363 xmlRelaxNGValidStatePtr state; /* the current validation state */
364 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000365
Daniel Veillard4c004142003-10-07 11:33:24 +0000366 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
367 int freeStatesNr;
368 int freeStatesMax;
369 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000370
371 /*
372 * This is used for "progressive" validation
373 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000374 xmlRegExecCtxtPtr elem; /* the current element regexp */
375 int elemNr; /* the number of element validated */
376 int elemMax; /* the max depth of elements */
377 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
378 int pstate; /* progressive state */
379 xmlNodePtr pnode; /* the current node */
380 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
381 int perr; /* signal error in content model
382 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000383};
384
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000385/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000386 * xmlRelaxNGInclude:
387 *
388 * Structure associated to a RelaxNGs document element
389 */
390struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000391 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
392 xmlChar *href; /* the normalized href value */
393 xmlDocPtr doc; /* the associated XML document */
394 xmlRelaxNGDefinePtr content; /* the definitions */
395 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000396};
397
398/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000399 * xmlRelaxNGDocument:
400 *
401 * Structure associated to a RelaxNGs document element
402 */
403struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000404 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000405 xmlChar *href; /* the normalized href value */
406 xmlDocPtr doc; /* the associated XML document */
407 xmlRelaxNGDefinePtr content; /* the definitions */
408 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000409};
410
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000411
Daniel Veillard6eadf632003-01-23 18:29:16 +0000412/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000413 * *
414 * Some factorized error routines *
415 * *
416 ************************************************************************/
417
418/**
419 * xmlRngPErrMemory:
420 * @ctxt: an Relax-NG parser context
421 * @extra: extra informations
422 *
423 * Handle a redefinition of attribute error
424 */
425static void
426xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
427{
428 xmlGenericErrorFunc channel = NULL;
429 void *data = NULL;
430
431 if (ctxt != NULL) {
432 channel = ctxt->error;
433 data = ctxt->userData;
434 ctxt->nbErrors++;
435 }
436 if (extra)
437 __xmlRaiseError(channel, data,
438 NULL, NULL, XML_FROM_RELAXNGP,
439 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
440 NULL, NULL, 0, 0,
441 "Memory allocation failed : %s\n", extra);
442 else
443 __xmlRaiseError(channel, data,
444 NULL, NULL, XML_FROM_RELAXNGP,
445 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
446 NULL, NULL, 0, 0, "Memory allocation failed\n");
447}
448
449/**
450 * xmlRngVErrMemory:
451 * @ctxt: a Relax-NG validation context
452 * @extra: extra informations
453 *
454 * Handle a redefinition of attribute error
455 */
456static void
457xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
458{
459 xmlGenericErrorFunc channel = NULL;
460 void *data = NULL;
461
462 if (ctxt != NULL) {
463 channel = ctxt->error;
464 data = ctxt->userData;
465 ctxt->nbErrors++;
466 }
467 if (extra)
468 __xmlRaiseError(channel, data,
469 NULL, NULL, XML_FROM_RELAXNGV,
470 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
471 NULL, NULL, 0, 0,
472 "Memory allocation failed : %s\n", extra);
473 else
474 __xmlRaiseError(channel, data,
475 NULL, NULL, XML_FROM_RELAXNGV,
476 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
477 NULL, NULL, 0, 0, "Memory allocation failed\n");
478}
479
480/**
481 * xmlRngPErr:
482 * @ctxt: a Relax-NG parser context
483 * @node: the node raising the error
484 * @error: the error code
485 * @msg: message
486 * @str1: extra info
487 * @str2: extra info
488 *
489 * Handle a Relax NG Parsing error
490 */
491static void
492xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
493 const char *msg, const xmlChar * str1, const xmlChar * str2)
494{
495 xmlGenericErrorFunc channel = NULL;
496 void *data = NULL;
497
498 if (ctxt != NULL) {
499 channel = ctxt->error;
500 data = ctxt->userData;
501 ctxt->nbErrors++;
502 }
503 __xmlRaiseError(channel, data,
504 NULL, node, XML_FROM_RELAXNGP,
505 error, XML_ERR_ERROR, NULL, 0,
506 (const char *) str1, (const char *) str2, NULL, 0, 0,
507 msg, str1, str2);
508}
509
510/**
511 * xmlRngVErr:
512 * @ctxt: a Relax-NG validation context
513 * @node: the node raising the error
514 * @error: the error code
515 * @msg: message
516 * @str1: extra info
517 * @str2: extra info
518 *
519 * Handle a Relax NG Validation error
520 */
521static void
522xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
523 const char *msg, const xmlChar * str1, const xmlChar * str2)
524{
525 xmlGenericErrorFunc channel = NULL;
526 void *data = NULL;
527
528 if (ctxt != NULL) {
529 channel = ctxt->error;
530 data = ctxt->userData;
531 ctxt->nbErrors++;
532 }
533 __xmlRaiseError(channel, data,
534 NULL, node, XML_FROM_RELAXNGV,
535 error, XML_ERR_ERROR, NULL, 0,
536 (const char *) str1, (const char *) str2, NULL, 0, 0,
537 msg, str1, str2);
538}
539
540/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000541 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000542 * Preliminary type checking interfaces *
543 * *
544 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000545
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000546/**
547 * xmlRelaxNGTypeHave:
548 * @data: data needed for the library
549 * @type: the type name
550 * @value: the value to check
551 *
552 * Function provided by a type library to check if a type is exported
553 *
554 * Returns 1 if yes, 0 if no and -1 in case of error.
555 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000556typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000557
558/**
559 * xmlRelaxNGTypeCheck:
560 * @data: data needed for the library
561 * @type: the type name
562 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000563 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000564 *
565 * Function provided by a type library to check if a value match a type
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 (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
570 const xmlChar * value, void **result,
571 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000572
573/**
574 * xmlRelaxNGFacetCheck:
575 * @data: data needed for the library
576 * @type: the type name
577 * @facet: the facet name
578 * @val: the facet value
579 * @strval: the string value
580 * @value: the value to check
581 *
582 * Function provided by a type library to check a value facet
583 *
584 * Returns 1 if yes, 0 if no and -1 in case of error.
585 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000586typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
587 const xmlChar * facet,
588 const xmlChar * val,
589 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000590
591/**
592 * xmlRelaxNGTypeFree:
593 * @data: data needed for the library
594 * @result: the value to free
595 *
596 * Function provided by a type library to free a returned result
597 */
598typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000599
600/**
601 * xmlRelaxNGTypeCompare:
602 * @data: data needed for the library
603 * @type: the type name
604 * @value1: the first value
605 * @value2: the second value
606 *
607 * Function provided by a type library to compare two values accordingly
608 * to a type.
609 *
610 * Returns 1 if yes, 0 if no and -1 in case of error.
611 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000612typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
613 const xmlChar * value1,
614 xmlNodePtr ctxt1,
615 void *comp1,
616 const xmlChar * value2,
617 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000618typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
619typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
620struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000621 const xmlChar *namespace; /* the datatypeLibrary value */
622 void *data; /* data needed for the library */
623 xmlRelaxNGTypeHave have; /* the export function */
624 xmlRelaxNGTypeCheck check; /* the checking function */
625 xmlRelaxNGTypeCompare comp; /* the compare function */
626 xmlRelaxNGFacetCheck facet; /* the facet check function */
627 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000628};
629
630/************************************************************************
631 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000632 * Allocation functions *
633 * *
634 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000635static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
636static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000637static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000638static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000639static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
640 ATTRIBUTE_UNUSED,
641 xmlRelaxNGValidStatePtr state1,
642 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000643static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000644 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000645
646/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000647 * xmlRelaxNGFreeDocument:
648 * @docu: a document structure
649 *
650 * Deallocate a RelaxNG document structure.
651 */
652static void
653xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
654{
655 if (docu == NULL)
656 return;
657
658 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000659 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000660 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000661 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000662 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000663 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000664 xmlFree(docu);
665}
666
667/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000668 * xmlRelaxNGFreeDocumentList:
669 * @docu: a list of document structure
670 *
671 * Deallocate a RelaxNG document structures.
672 */
673static void
674xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
675{
676 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000677
Daniel Veillardc482e262003-02-26 14:48:48 +0000678 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000679 next = docu->next;
680 xmlRelaxNGFreeDocument(docu);
681 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000682 }
683}
684
685/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000686 * xmlRelaxNGFreeInclude:
687 * @incl: a include structure
688 *
689 * Deallocate a RelaxNG include structure.
690 */
691static void
692xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
693{
694 if (incl == NULL)
695 return;
696
697 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000698 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000699 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000700 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000701 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000702 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000703 xmlFree(incl);
704}
705
706/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000707 * xmlRelaxNGFreeIncludeList:
708 * @incl: a include structure list
709 *
710 * Deallocate a RelaxNG include structure.
711 */
712static void
713xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
714{
715 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000716
Daniel Veillardc482e262003-02-26 14:48:48 +0000717 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000718 next = incl->next;
719 xmlRelaxNGFreeInclude(incl);
720 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000721 }
722}
723
724/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000725 * xmlRelaxNGNewRelaxNG:
726 * @ctxt: a Relax-NG validation context (optional)
727 *
728 * Allocate a new RelaxNG structure.
729 *
730 * Returns the newly allocated structure or NULL in case or error
731 */
732static xmlRelaxNGPtr
733xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
734{
735 xmlRelaxNGPtr ret;
736
737 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
738 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000739 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000740 return (NULL);
741 }
742 memset(ret, 0, sizeof(xmlRelaxNG));
743
744 return (ret);
745}
746
747/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000748 * xmlRelaxNGFreeInnerSchema:
749 * @schema: a schema structure
750 *
751 * Deallocate a RelaxNG schema structure.
752 */
753static void
754xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
755{
756 if (schema == NULL)
757 return;
758
759 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000760 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000761 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000762 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000763
Daniel Veillard4c004142003-10-07 11:33:24 +0000764 for (i = 0; i < schema->defNr; i++)
765 xmlRelaxNGFreeDefine(schema->defTab[i]);
766 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000767 }
768
769 xmlFree(schema);
770}
771
772/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000773 * xmlRelaxNGFree:
774 * @schema: a schema structure
775 *
776 * Deallocate a RelaxNG structure.
777 */
778void
779xmlRelaxNGFree(xmlRelaxNGPtr schema)
780{
781 if (schema == NULL)
782 return;
783
Daniel Veillard6eadf632003-01-23 18:29:16 +0000784 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000785 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000786 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000787 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000788 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000789 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000790 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000791 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000792 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000793 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000794
Daniel Veillard4c004142003-10-07 11:33:24 +0000795 for (i = 0; i < schema->defNr; i++)
796 xmlRelaxNGFreeDefine(schema->defTab[i]);
797 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000798 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000799
800 xmlFree(schema);
801}
802
803/**
804 * xmlRelaxNGNewGrammar:
805 * @ctxt: a Relax-NG validation context (optional)
806 *
807 * Allocate a new RelaxNG grammar.
808 *
809 * Returns the newly allocated structure or NULL in case or error
810 */
811static xmlRelaxNGGrammarPtr
812xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
813{
814 xmlRelaxNGGrammarPtr ret;
815
816 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
817 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000818 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000819 return (NULL);
820 }
821 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
822
823 return (ret);
824}
825
826/**
827 * xmlRelaxNGFreeGrammar:
828 * @grammar: a grammar structure
829 *
830 * Deallocate a RelaxNG grammar structure.
831 */
832static void
833xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
834{
835 if (grammar == NULL)
836 return;
837
Daniel Veillardc482e262003-02-26 14:48:48 +0000838 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000839 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000840 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000841 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000842 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000843 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000844 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000845 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000846 }
847 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000848 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000849 }
850
851 xmlFree(grammar);
852}
853
854/**
855 * xmlRelaxNGNewDefine:
856 * @ctxt: a Relax-NG validation context
857 * @node: the node in the input document.
858 *
859 * Allocate a new RelaxNG define.
860 *
861 * Returns the newly allocated structure or NULL in case or error
862 */
863static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000864xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000865{
866 xmlRelaxNGDefinePtr ret;
867
Daniel Veillard419a7682003-02-03 23:22:49 +0000868 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000869 ctxt->defMax = 16;
870 ctxt->defNr = 0;
871 ctxt->defTab = (xmlRelaxNGDefinePtr *)
872 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
873 if (ctxt->defTab == NULL) {
874 xmlRngPErrMemory(ctxt, "allocating define\n");
875 return (NULL);
876 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000877 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000878 xmlRelaxNGDefinePtr *tmp;
879
880 ctxt->defMax *= 2;
881 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
882 ctxt->defMax *
883 sizeof
884 (xmlRelaxNGDefinePtr));
885 if (tmp == NULL) {
886 xmlRngPErrMemory(ctxt, "allocating define\n");
887 return (NULL);
888 }
889 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000890 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000891 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
892 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000893 xmlRngPErrMemory(ctxt, "allocating define\n");
894 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000895 }
896 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000897 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000898 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000899 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000900 return (ret);
901}
902
903/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000904 * xmlRelaxNGFreePartition:
905 * @partitions: a partition set structure
906 *
907 * Deallocate RelaxNG partition set structures.
908 */
909static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000910xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
911{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000912 xmlRelaxNGInterleaveGroupPtr group;
913 int j;
914
915 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000916 if (partitions->groups != NULL) {
917 for (j = 0; j < partitions->nbgroups; j++) {
918 group = partitions->groups[j];
919 if (group != NULL) {
920 if (group->defs != NULL)
921 xmlFree(group->defs);
922 if (group->attrs != NULL)
923 xmlFree(group->attrs);
924 xmlFree(group);
925 }
926 }
927 xmlFree(partitions->groups);
928 }
929 if (partitions->triage != NULL) {
930 xmlHashFree(partitions->triage, NULL);
931 }
932 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000933 }
934}
Daniel Veillard4c004142003-10-07 11:33:24 +0000935
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000936/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000937 * xmlRelaxNGFreeDefine:
938 * @define: a define structure
939 *
940 * Deallocate a RelaxNG define structure.
941 */
942static void
943xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
944{
945 if (define == NULL)
946 return;
947
Daniel Veillard4c004142003-10-07 11:33:24 +0000948 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
949 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000950
Daniel Veillard4c004142003-10-07 11:33:24 +0000951 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
952 if ((lib != NULL) && (lib->freef != NULL))
953 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000954 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000955 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
956 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
957 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
958 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000959 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000960 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000961 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000962 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000963 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000964 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000965 if (define->contModel != NULL)
966 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000967 xmlFree(define);
968}
969
970/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000971 * xmlRelaxNGNewStates:
972 * @ctxt: a Relax-NG validation context
973 * @size: the default size for the container
974 *
975 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000976 *
977 * Returns the newly allocated structure or NULL in case or error
978 */
979static xmlRelaxNGStatesPtr
980xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
981{
982 xmlRelaxNGStatesPtr ret;
983
Daniel Veillard798024a2003-03-19 10:36:09 +0000984 if ((ctxt != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +0000985 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
986 ctxt->freeStatesNr--;
987 ret = ctxt->freeStates[ctxt->freeStatesNr];
988 ret->nbState = 0;
989 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +0000990 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000991 if (size < 16)
992 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000993
994 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +0000995 (size -
996 1) *
997 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +0000998 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000999 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001000 return (NULL);
1001 }
1002 ret->nbState = 0;
1003 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001004 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1005 sizeof
1006 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001007 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001008 xmlRngVErrMemory(ctxt, "allocating states\n");
1009 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001010 return (NULL);
1011 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001012 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001013}
1014
1015/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001016 * xmlRelaxNGAddStateUniq:
1017 * @ctxt: a Relax-NG validation context
1018 * @states: the states container
1019 * @state: the validation state
1020 *
1021 * Add a RelaxNG validation state to the container without checking
1022 * for unicity.
1023 *
1024 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1025 */
1026static int
1027xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001028 xmlRelaxNGStatesPtr states,
1029 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001030{
1031 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001032 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001033 }
1034 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001035 xmlRelaxNGValidStatePtr *tmp;
1036 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001037
Daniel Veillard4c004142003-10-07 11:33:24 +00001038 size = states->maxState * 2;
1039 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1040 (size) *
1041 sizeof
1042 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001043 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001044 xmlRngVErrMemory(ctxt, "adding states\n");
1045 return (-1);
1046 }
1047 states->tabState = tmp;
1048 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001049 }
1050 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001051 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001052}
1053
1054/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001055 * xmlRelaxNGAddState:
1056 * @ctxt: a Relax-NG validation context
1057 * @states: the states container
1058 * @state: the validation state
1059 *
1060 * Add a RelaxNG validation state to the container
1061 *
1062 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1063 */
1064static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001065xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1066 xmlRelaxNGStatesPtr states,
1067 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001068{
1069 int i;
1070
1071 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001072 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001073 }
1074 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001075 xmlRelaxNGValidStatePtr *tmp;
1076 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001077
Daniel Veillard4c004142003-10-07 11:33:24 +00001078 size = states->maxState * 2;
1079 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1080 (size) *
1081 sizeof
1082 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001083 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001084 xmlRngVErrMemory(ctxt, "adding states\n");
1085 return (-1);
1086 }
1087 states->tabState = tmp;
1088 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001089 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001090 for (i = 0; i < states->nbState; i++) {
1091 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1092 xmlRelaxNGFreeValidState(ctxt, state);
1093 return (0);
1094 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001095 }
1096 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001097 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001098}
1099
1100/**
1101 * xmlRelaxNGFreeStates:
1102 * @ctxt: a Relax-NG validation context
1103 * @states: teh container
1104 *
1105 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001106 */
1107static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001108xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001109 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001110{
Daniel Veillard798024a2003-03-19 10:36:09 +00001111 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001112 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001113 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001114 ctxt->freeStatesMax = 40;
1115 ctxt->freeStatesNr = 0;
1116 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1117 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1118 if (ctxt->freeStates == NULL) {
1119 xmlRngVErrMemory(ctxt, "storing states\n");
1120 }
1121 } else if ((ctxt != NULL)
1122 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1123 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001124
Daniel Veillard4c004142003-10-07 11:33:24 +00001125 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1126 2 * ctxt->freeStatesMax *
1127 sizeof
1128 (xmlRelaxNGStatesPtr));
1129 if (tmp == NULL) {
1130 xmlRngVErrMemory(ctxt, "storing states\n");
1131 xmlFree(states->tabState);
1132 xmlFree(states);
1133 return;
1134 }
1135 ctxt->freeStates = tmp;
1136 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001137 }
1138 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001139 xmlFree(states->tabState);
1140 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001141 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001142 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001143 }
1144}
1145
1146/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001147 * xmlRelaxNGNewValidState:
1148 * @ctxt: a Relax-NG validation context
1149 * @node: the current node or NULL for the document
1150 *
1151 * Allocate a new RelaxNG validation state
1152 *
1153 * Returns the newly allocated structure or NULL in case or error
1154 */
1155static xmlRelaxNGValidStatePtr
1156xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1157{
1158 xmlRelaxNGValidStatePtr ret;
1159 xmlAttrPtr attr;
1160 xmlAttrPtr attrs[MAX_ATTR];
1161 int nbAttrs = 0;
1162 xmlNodePtr root = NULL;
1163
1164 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001165 root = xmlDocGetRootElement(ctxt->doc);
1166 if (root == NULL)
1167 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001168 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001169 attr = node->properties;
1170 while (attr != NULL) {
1171 if (nbAttrs < MAX_ATTR)
1172 attrs[nbAttrs++] = attr;
1173 else
1174 nbAttrs++;
1175 attr = attr->next;
1176 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001177 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001178 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1179 ctxt->freeState->nbState--;
1180 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001181 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001182 ret =
1183 (xmlRelaxNGValidStatePtr)
1184 xmlMalloc(sizeof(xmlRelaxNGValidState));
1185 if (ret == NULL) {
1186 xmlRngVErrMemory(ctxt, "allocating states\n");
1187 return (NULL);
1188 }
1189 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001190 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001191 ret->value = NULL;
1192 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001193 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001194 ret->node = (xmlNodePtr) ctxt->doc;
1195 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001196 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001197 ret->node = node;
1198 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001199 }
1200 ret->nbAttrs = 0;
1201 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001202 if (ret->attrs == NULL) {
1203 if (nbAttrs < 4)
1204 ret->maxAttrs = 4;
1205 else
1206 ret->maxAttrs = nbAttrs;
1207 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1208 sizeof(xmlAttrPtr));
1209 if (ret->attrs == NULL) {
1210 xmlRngVErrMemory(ctxt, "allocating states\n");
1211 return (ret);
1212 }
1213 } else if (ret->maxAttrs < nbAttrs) {
1214 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001215
Daniel Veillard4c004142003-10-07 11:33:24 +00001216 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1217 sizeof(xmlAttrPtr));
1218 if (tmp == NULL) {
1219 xmlRngVErrMemory(ctxt, "allocating states\n");
1220 return (ret);
1221 }
1222 ret->attrs = tmp;
1223 ret->maxAttrs = nbAttrs;
1224 }
1225 ret->nbAttrs = nbAttrs;
1226 if (nbAttrs < MAX_ATTR) {
1227 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1228 } else {
1229 attr = node->properties;
1230 nbAttrs = 0;
1231 while (attr != NULL) {
1232 ret->attrs[nbAttrs++] = attr;
1233 attr = attr->next;
1234 }
1235 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001236 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001237 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001238 return (ret);
1239}
1240
1241/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001242 * xmlRelaxNGCopyValidState:
1243 * @ctxt: a Relax-NG validation context
1244 * @state: a validation state
1245 *
1246 * Copy the validation state
1247 *
1248 * Returns the newly allocated structure or NULL in case or error
1249 */
1250static xmlRelaxNGValidStatePtr
1251xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001252 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001253{
1254 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001255 unsigned int maxAttrs;
1256 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001257
1258 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001259 return (NULL);
1260 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1261 ctxt->freeState->nbState--;
1262 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001263 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001264 ret =
1265 (xmlRelaxNGValidStatePtr)
1266 xmlMalloc(sizeof(xmlRelaxNGValidState));
1267 if (ret == NULL) {
1268 xmlRngVErrMemory(ctxt, "allocating states\n");
1269 return (NULL);
1270 }
1271 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001272 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001273 attrs = ret->attrs;
1274 maxAttrs = ret->maxAttrs;
1275 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1276 ret->attrs = attrs;
1277 ret->maxAttrs = maxAttrs;
1278 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001279 if (ret->attrs == NULL) {
1280 ret->maxAttrs = state->maxAttrs;
1281 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1282 sizeof(xmlAttrPtr));
1283 if (ret->attrs == NULL) {
1284 xmlRngVErrMemory(ctxt, "allocating states\n");
1285 ret->nbAttrs = 0;
1286 return (ret);
1287 }
1288 } else if (ret->maxAttrs < state->nbAttrs) {
1289 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001290
Daniel Veillard4c004142003-10-07 11:33:24 +00001291 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1292 sizeof(xmlAttrPtr));
1293 if (tmp == NULL) {
1294 xmlRngVErrMemory(ctxt, "allocating states\n");
1295 ret->nbAttrs = 0;
1296 return (ret);
1297 }
1298 ret->maxAttrs = state->maxAttrs;
1299 ret->attrs = tmp;
1300 }
1301 memcpy(ret->attrs, state->attrs,
1302 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001303 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001304 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001305}
1306
1307/**
1308 * xmlRelaxNGEqualValidState:
1309 * @ctxt: a Relax-NG validation context
1310 * @state1: a validation state
1311 * @state2: a validation state
1312 *
1313 * Compare the validation states for equality
1314 *
1315 * Returns 1 if equald, 0 otherwise
1316 */
1317static int
1318xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001319 xmlRelaxNGValidStatePtr state1,
1320 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001321{
1322 int i;
1323
1324 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001325 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001326 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001327 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001328 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001329 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001330 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001331 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001332 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001333 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001334 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001335 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001336 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001337 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001338 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001339 (!xmlStrEqual(state1->value, state2->value)))
1340 return (0);
1341 for (i = 0; i < state1->nbAttrs; i++) {
1342 if (state1->attrs[i] != state2->attrs[i])
1343 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001344 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001345 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001346}
1347
1348/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001349 * xmlRelaxNGFreeValidState:
1350 * @state: a validation state structure
1351 *
1352 * Deallocate a RelaxNG validation state structure.
1353 */
1354static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001355xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001356 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001357{
1358 if (state == NULL)
1359 return;
1360
Daniel Veillard798024a2003-03-19 10:36:09 +00001361 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001362 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001363 }
1364 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001365 if (state->attrs != NULL)
1366 xmlFree(state->attrs);
1367 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001368 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001369 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001370 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001371}
1372
1373/************************************************************************
1374 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001375 * Document functions *
1376 * *
1377 ************************************************************************/
1378static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001379 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001380
1381/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001382 * xmlRelaxNGIncludePush:
1383 * @ctxt: the parser context
1384 * @value: the element doc
1385 *
1386 * Pushes a new include on top of the include stack
1387 *
1388 * Returns 0 in case of error, the index in the stack otherwise
1389 */
1390static int
1391xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001392 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001393{
1394 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001395 ctxt->incMax = 4;
1396 ctxt->incNr = 0;
1397 ctxt->incTab =
1398 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1399 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001400 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001401 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001402 return (0);
1403 }
1404 }
1405 if (ctxt->incNr >= ctxt->incMax) {
1406 ctxt->incMax *= 2;
1407 ctxt->incTab =
1408 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001409 ctxt->incMax *
1410 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001411 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001412 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001413 return (0);
1414 }
1415 }
1416 ctxt->incTab[ctxt->incNr] = value;
1417 ctxt->inc = value;
1418 return (ctxt->incNr++);
1419}
1420
1421/**
1422 * xmlRelaxNGIncludePop:
1423 * @ctxt: the parser context
1424 *
1425 * Pops the top include from the include stack
1426 *
1427 * Returns the include just removed
1428 */
1429static xmlRelaxNGIncludePtr
1430xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1431{
1432 xmlRelaxNGIncludePtr ret;
1433
1434 if (ctxt->incNr <= 0)
1435 return (0);
1436 ctxt->incNr--;
1437 if (ctxt->incNr > 0)
1438 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1439 else
1440 ctxt->inc = NULL;
1441 ret = ctxt->incTab[ctxt->incNr];
1442 ctxt->incTab[ctxt->incNr] = 0;
1443 return (ret);
1444}
1445
1446/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001447 * xmlRelaxNGRemoveRedefine:
1448 * @ctxt: the parser context
1449 * @URL: the normalized URL
1450 * @target: the included target
1451 * @name: the define name to eliminate
1452 *
1453 * Applies the elimination algorithm of 4.7
1454 *
1455 * Returns 0 in case of error, 1 in case of success.
1456 */
1457static int
1458xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001459 const xmlChar * URL ATTRIBUTE_UNUSED,
1460 xmlNodePtr target, const xmlChar * name)
1461{
Daniel Veillard5add8682003-03-10 13:13:58 +00001462 int found = 0;
1463 xmlNodePtr tmp, tmp2;
1464 xmlChar *name2;
1465
1466#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001467 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001468 xmlGenericError(xmlGenericErrorContext,
1469 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001470 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001471 xmlGenericError(xmlGenericErrorContext,
1472 "Elimination of <include> define %s from %s\n",
1473 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001474#endif
1475 tmp = target;
1476 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001477 tmp2 = tmp->next;
1478 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1479 found = 1;
1480 xmlUnlinkNode(tmp);
1481 xmlFreeNode(tmp);
1482 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1483 name2 = xmlGetProp(tmp, BAD_CAST "name");
1484 xmlRelaxNGNormExtSpace(name2);
1485 if (name2 != NULL) {
1486 if (xmlStrEqual(name, name2)) {
1487 found = 1;
1488 xmlUnlinkNode(tmp);
1489 xmlFreeNode(tmp);
1490 }
1491 xmlFree(name2);
1492 }
1493 } else if (IS_RELAXNG(tmp, "include")) {
1494 xmlChar *href = NULL;
1495 xmlRelaxNGDocumentPtr inc = tmp->_private;
Daniel Veillard5add8682003-03-10 13:13:58 +00001496
Daniel Veillard4c004142003-10-07 11:33:24 +00001497 if ((inc != NULL) && (inc->doc != NULL) &&
1498 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001499
Daniel Veillard4c004142003-10-07 11:33:24 +00001500 if (xmlStrEqual
1501 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001502#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001503 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001504#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001505 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1506 inc->doc->children->
1507 children, name) == 1) {
1508 found = 1;
1509 }
1510 if (href != NULL)
1511 xmlFree(href);
1512 }
1513 }
1514 }
1515 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001516 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001517 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001518}
1519
1520/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001521 * xmlRelaxNGLoadInclude:
1522 * @ctxt: the parser context
1523 * @URL: the normalized URL
1524 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001525 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001526 *
1527 * First lookup if the document is already loaded into the parser context,
1528 * check against recursion. If not found the resource is loaded and
1529 * the content is preprocessed before being returned back to the caller.
1530 *
1531 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1532 */
1533static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001534xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1535 xmlNodePtr node, const xmlChar * ns)
1536{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001537 xmlRelaxNGIncludePtr ret = NULL;
1538 xmlDocPtr doc;
1539 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001540 xmlNodePtr root, cur;
1541
1542#ifdef DEBUG_INCLUDE
1543 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001544 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001545#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001546
1547 /*
1548 * check against recursion in the stack
1549 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001550 for (i = 0; i < ctxt->incNr; i++) {
1551 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1552 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1553 "Detected an Include recursion for %s\n", URL,
1554 NULL);
1555 return (NULL);
1556 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001557 }
1558
1559 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001560 * load the document
1561 */
1562 doc = xmlParseFile((const char *) URL);
1563 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001564 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1565 "xmlRelaxNG: could not load %s\n", URL, NULL);
1566 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001567 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001568#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001569 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001570#endif
1571
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001572 /*
1573 * Allocate the document structures and register it first.
1574 */
1575 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1576 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001577 xmlRngPErrMemory(ctxt, "allocating include\n");
1578 xmlFreeDoc(doc);
1579 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001580 }
1581 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1582 ret->doc = doc;
1583 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001584 ret->next = ctxt->includes;
1585 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001586
1587 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001588 * transmit the ns if needed
1589 */
1590 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001591 root = xmlDocGetRootElement(doc);
1592 if (root != NULL) {
1593 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1594 xmlSetProp(root, BAD_CAST "ns", ns);
1595 }
1596 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001597 }
1598
1599 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001600 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001601 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001602 xmlRelaxNGIncludePush(ctxt, ret);
1603
1604 /*
1605 * Some preprocessing of the document content, this include recursing
1606 * in the include stack.
1607 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001608#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001609 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001610#endif
1611
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001612 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1613 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001614 ctxt->inc = NULL;
1615 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001616 }
1617
1618 /*
1619 * Pop up the include from the stack
1620 */
1621 xmlRelaxNGIncludePop(ctxt);
1622
Daniel Veillard5add8682003-03-10 13:13:58 +00001623#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001624 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001625#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001626 /*
1627 * Check that the top element is a grammar
1628 */
1629 root = xmlDocGetRootElement(doc);
1630 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001631 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1632 "xmlRelaxNG: included document is empty %s\n", URL,
1633 NULL);
1634 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001635 }
1636 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001637 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1638 "xmlRelaxNG: included document %s root is not a grammar\n",
1639 URL, NULL);
1640 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001641 }
1642
1643 /*
1644 * Elimination of redefined rules in the include.
1645 */
1646 cur = node->children;
1647 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001648 if (IS_RELAXNG(cur, "start")) {
1649 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001650
Daniel Veillard4c004142003-10-07 11:33:24 +00001651 found =
1652 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1653 if (!found) {
1654 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1655 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1656 URL, NULL);
1657 }
1658 } else if (IS_RELAXNG(cur, "define")) {
1659 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001660
Daniel Veillard4c004142003-10-07 11:33:24 +00001661 name = xmlGetProp(cur, BAD_CAST "name");
1662 if (name == NULL) {
1663 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1664 "xmlRelaxNG: include %s has define without name\n",
1665 URL, NULL);
1666 } else {
1667 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001668
Daniel Veillard4c004142003-10-07 11:33:24 +00001669 xmlRelaxNGNormExtSpace(name);
1670 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1671 root->children, name);
1672 if (!found) {
1673 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1674 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1675 URL, name);
1676 }
1677 xmlFree(name);
1678 }
1679 }
1680 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001681 }
1682
1683
Daniel Veillard4c004142003-10-07 11:33:24 +00001684 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001685}
1686
1687/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001688 * xmlRelaxNGValidErrorPush:
1689 * @ctxt: the validation context
1690 * @err: the error code
1691 * @arg1: the first string argument
1692 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001693 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001694 *
1695 * Pushes a new error on top of the error stack
1696 *
1697 * Returns 0 in case of error, the index in the stack otherwise
1698 */
1699static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001700xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1701 xmlRelaxNGValidErr err, const xmlChar * arg1,
1702 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001703{
1704 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001705
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001706#ifdef DEBUG_ERROR
1707 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001708 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001709#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001710 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001711 ctxt->errMax = 8;
1712 ctxt->errNr = 0;
1713 ctxt->errTab =
1714 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1715 sizeof
1716 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001717 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001718 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001719 return (0);
1720 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001721 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001722 }
1723 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001724 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001725 ctxt->errTab =
1726 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001727 ctxt->errMax *
1728 sizeof
1729 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001730 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001731 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001732 return (0);
1733 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001734 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001735 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001736 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001737 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1738 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001739 cur = &ctxt->errTab[ctxt->errNr];
1740 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001741 if (dup) {
1742 cur->arg1 = xmlStrdup(arg1);
1743 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001744 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001745 } else {
1746 cur->arg1 = arg1;
1747 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001748 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001749 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001750 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001751 cur->node = ctxt->state->node;
1752 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001753 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001754 cur->node = NULL;
1755 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001756 }
1757 ctxt->err = cur;
1758 return (ctxt->errNr++);
1759}
1760
1761/**
1762 * xmlRelaxNGValidErrorPop:
1763 * @ctxt: the validation context
1764 *
1765 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001766 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001767static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001768xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1769{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001770 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001771
Daniel Veillard580ced82003-03-21 21:22:48 +00001772 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001773 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001774 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001775 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001776 ctxt->errNr--;
1777 if (ctxt->errNr > 0)
1778 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1779 else
1780 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001781 cur = &ctxt->errTab[ctxt->errNr];
1782 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001783 if (cur->arg1 != NULL)
1784 xmlFree((xmlChar *) cur->arg1);
1785 cur->arg1 = NULL;
1786 if (cur->arg2 != NULL)
1787 xmlFree((xmlChar *) cur->arg2);
1788 cur->arg2 = NULL;
1789 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001790 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001791}
1792
Daniel Veillard42f12e92003-03-07 18:32:59 +00001793/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001794 * xmlRelaxNGDocumentPush:
1795 * @ctxt: the parser context
1796 * @value: the element doc
1797 *
1798 * Pushes a new doc on top of the doc stack
1799 *
1800 * Returns 0 in case of error, the index in the stack otherwise
1801 */
1802static int
1803xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001804 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001805{
1806 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001807 ctxt->docMax = 4;
1808 ctxt->docNr = 0;
1809 ctxt->docTab =
1810 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1811 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001812 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001813 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001814 return (0);
1815 }
1816 }
1817 if (ctxt->docNr >= ctxt->docMax) {
1818 ctxt->docMax *= 2;
1819 ctxt->docTab =
1820 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001821 ctxt->docMax *
1822 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001823 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001824 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001825 return (0);
1826 }
1827 }
1828 ctxt->docTab[ctxt->docNr] = value;
1829 ctxt->doc = value;
1830 return (ctxt->docNr++);
1831}
1832
1833/**
1834 * xmlRelaxNGDocumentPop:
1835 * @ctxt: the parser context
1836 *
1837 * Pops the top doc from the doc stack
1838 *
1839 * Returns the doc just removed
1840 */
1841static xmlRelaxNGDocumentPtr
1842xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1843{
1844 xmlRelaxNGDocumentPtr ret;
1845
1846 if (ctxt->docNr <= 0)
1847 return (0);
1848 ctxt->docNr--;
1849 if (ctxt->docNr > 0)
1850 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1851 else
1852 ctxt->doc = NULL;
1853 ret = ctxt->docTab[ctxt->docNr];
1854 ctxt->docTab[ctxt->docNr] = 0;
1855 return (ret);
1856}
1857
1858/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001859 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001860 * @ctxt: the parser context
1861 * @URL: the normalized URL
1862 * @ns: the inherited ns if any
1863 *
1864 * First lookup if the document is already loaded into the parser context,
1865 * check against recursion. If not found the resource is loaded and
1866 * the content is preprocessed before being returned back to the caller.
1867 *
1868 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1869 */
1870static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001871xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1872 const xmlChar * URL, const xmlChar * ns)
1873{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001874 xmlRelaxNGDocumentPtr ret = NULL;
1875 xmlDocPtr doc;
1876 xmlNodePtr root;
1877 int i;
1878
1879 /*
1880 * check against recursion in the stack
1881 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001882 for (i = 0; i < ctxt->docNr; i++) {
1883 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1884 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1885 "Detected an externalRef recursion for %s\n", URL,
1886 NULL);
1887 return (NULL);
1888 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001889 }
1890
1891 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001892 * load the document
1893 */
1894 doc = xmlParseFile((const char *) URL);
1895 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001896 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1897 "xmlRelaxNG: could not load %s\n", URL, NULL);
1898 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001899 }
1900
1901 /*
1902 * Allocate the document structures and register it first.
1903 */
1904 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1905 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001906 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1907 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1908 xmlFreeDoc(doc);
1909 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001910 }
1911 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1912 ret->doc = doc;
1913 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001914 ret->next = ctxt->documents;
1915 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001916
1917 /*
1918 * transmit the ns if needed
1919 */
1920 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001921 root = xmlDocGetRootElement(doc);
1922 if (root != NULL) {
1923 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1924 xmlSetProp(root, BAD_CAST "ns", ns);
1925 }
1926 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001927 }
1928
1929 /*
1930 * push it on the stack and register it in the hash table
1931 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001932 xmlRelaxNGDocumentPush(ctxt, ret);
1933
1934 /*
1935 * Some preprocessing of the document content
1936 */
1937 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1938 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001939 ctxt->doc = NULL;
1940 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001941 }
1942
1943 xmlRelaxNGDocumentPop(ctxt);
1944
Daniel Veillard4c004142003-10-07 11:33:24 +00001945 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001946}
1947
1948/************************************************************************
1949 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001950 * Error functions *
1951 * *
1952 ************************************************************************/
1953
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001954#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1955#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1956#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1957#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1958#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001959
Daniel Veillard231d7912003-02-09 14:22:17 +00001960static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00001961xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
1962{
Daniel Veillard231d7912003-02-09 14:22:17 +00001963 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001964 return ("none");
1965 switch (def->type) {
1966 case XML_RELAXNG_EMPTY:
1967 return ("empty");
1968 case XML_RELAXNG_NOT_ALLOWED:
1969 return ("notAllowed");
1970 case XML_RELAXNG_EXCEPT:
1971 return ("except");
1972 case XML_RELAXNG_TEXT:
1973 return ("text");
1974 case XML_RELAXNG_ELEMENT:
1975 return ("element");
1976 case XML_RELAXNG_DATATYPE:
1977 return ("datatype");
1978 case XML_RELAXNG_VALUE:
1979 return ("value");
1980 case XML_RELAXNG_LIST:
1981 return ("list");
1982 case XML_RELAXNG_ATTRIBUTE:
1983 return ("attribute");
1984 case XML_RELAXNG_DEF:
1985 return ("def");
1986 case XML_RELAXNG_REF:
1987 return ("ref");
1988 case XML_RELAXNG_EXTERNALREF:
1989 return ("externalRef");
1990 case XML_RELAXNG_PARENTREF:
1991 return ("parentRef");
1992 case XML_RELAXNG_OPTIONAL:
1993 return ("optional");
1994 case XML_RELAXNG_ZEROORMORE:
1995 return ("zeroOrMore");
1996 case XML_RELAXNG_ONEORMORE:
1997 return ("oneOrMore");
1998 case XML_RELAXNG_CHOICE:
1999 return ("choice");
2000 case XML_RELAXNG_GROUP:
2001 return ("group");
2002 case XML_RELAXNG_INTERLEAVE:
2003 return ("interleave");
2004 case XML_RELAXNG_START:
2005 return ("start");
2006 case XML_RELAXNG_NOOP:
2007 return ("noop");
2008 case XML_RELAXNG_PARAM:
2009 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002010 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002011 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002012}
Daniel Veillardd2298792003-02-14 16:54:11 +00002013
Daniel Veillard6eadf632003-01-23 18:29:16 +00002014/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002015 * xmlRelaxNGGetErrorString:
2016 * @err: the error code
2017 * @arg1: the first string argument
2018 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002019 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002020 * computes a formatted error string for the given error code and args
2021 *
2022 * Returns the error string, it must be deallocated by the caller
2023 */
2024static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002025xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2026 const xmlChar * arg2)
2027{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002028 char msg[1000];
2029
2030 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002031 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002032 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002033 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002034
2035 msg[0] = 0;
2036 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002037 case XML_RELAXNG_OK:
2038 return (NULL);
2039 case XML_RELAXNG_ERR_MEMORY:
2040 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002041 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002042 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2043 break;
2044 case XML_RELAXNG_ERR_TYPEVAL:
2045 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2046 arg2);
2047 break;
2048 case XML_RELAXNG_ERR_DUPID:
2049 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2050 break;
2051 case XML_RELAXNG_ERR_TYPECMP:
2052 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2053 break;
2054 case XML_RELAXNG_ERR_NOSTATE:
2055 return (xmlCharStrdup("Internal error: no state\n"));
2056 case XML_RELAXNG_ERR_NODEFINE:
2057 return (xmlCharStrdup("Internal error: no define\n"));
2058 case XML_RELAXNG_ERR_INTERNAL:
2059 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2060 break;
2061 case XML_RELAXNG_ERR_LISTEXTRA:
2062 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2063 break;
2064 case XML_RELAXNG_ERR_INTERNODATA:
2065 return (xmlCharStrdup
2066 ("Internal: interleave block has no data\n"));
2067 case XML_RELAXNG_ERR_INTERSEQ:
2068 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2069 case XML_RELAXNG_ERR_INTEREXTRA:
2070 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2071 break;
2072 case XML_RELAXNG_ERR_ELEMNAME:
2073 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2074 arg2);
2075 break;
2076 case XML_RELAXNG_ERR_ELEMNONS:
2077 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2078 arg1);
2079 break;
2080 case XML_RELAXNG_ERR_ELEMWRONGNS:
2081 snprintf(msg, 1000,
2082 "Element %s has wrong namespace: expecting %s\n", arg1,
2083 arg2);
2084 break;
2085 case XML_RELAXNG_ERR_ELEMWRONG:
2086 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2087 break;
2088 case XML_RELAXNG_ERR_TEXTWRONG:
2089 snprintf(msg, 1000,
2090 "Did not expect text in element %s content\n", arg1);
2091 break;
2092 case XML_RELAXNG_ERR_ELEMEXTRANS:
2093 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2094 arg1);
2095 break;
2096 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2097 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2098 break;
2099 case XML_RELAXNG_ERR_NOELEM:
2100 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2101 arg1);
2102 break;
2103 case XML_RELAXNG_ERR_NOTELEM:
2104 return (xmlCharStrdup("Expecting an element got text\n"));
2105 case XML_RELAXNG_ERR_ATTRVALID:
2106 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2107 arg1);
2108 break;
2109 case XML_RELAXNG_ERR_CONTENTVALID:
2110 snprintf(msg, 1000, "Element %s failed to validate content\n",
2111 arg1);
2112 break;
2113 case XML_RELAXNG_ERR_EXTRACONTENT:
2114 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2115 arg1, arg2);
2116 break;
2117 case XML_RELAXNG_ERR_INVALIDATTR:
2118 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2119 arg1, arg2);
2120 break;
2121 case XML_RELAXNG_ERR_LACKDATA:
2122 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2123 arg1);
2124 break;
2125 case XML_RELAXNG_ERR_DATAELEM:
2126 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2127 arg1);
2128 break;
2129 case XML_RELAXNG_ERR_VALELEM:
2130 snprintf(msg, 1000, "Value element %s has child elements\n",
2131 arg1);
2132 break;
2133 case XML_RELAXNG_ERR_LISTELEM:
2134 snprintf(msg, 1000, "List element %s has child elements\n",
2135 arg1);
2136 break;
2137 case XML_RELAXNG_ERR_DATATYPE:
2138 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2139 break;
2140 case XML_RELAXNG_ERR_VALUE:
2141 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2142 break;
2143 case XML_RELAXNG_ERR_LIST:
2144 return (xmlCharStrdup("Error validating list\n"));
2145 case XML_RELAXNG_ERR_NOGRAMMAR:
2146 return (xmlCharStrdup("No top grammar defined\n"));
2147 case XML_RELAXNG_ERR_EXTRADATA:
2148 return (xmlCharStrdup("Extra data in the document\n"));
2149 default:
2150 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002151 }
2152 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002153 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002154 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002155 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002156 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002157}
2158
2159/**
2160 * xmlRelaxNGValidErrorContext:
2161 * @ctxt: the validation context
2162 * @node: the node
2163 * @child: the node child generating the problem.
2164 *
2165 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00002166 */
2167static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00002168xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00002169 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00002170{
2171 int line = 0;
2172 const xmlChar *file = NULL;
2173 const xmlChar *name = NULL;
2174 const char *type = "error";
2175
2176 if ((ctxt == NULL) || (ctxt->error == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002177 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002178
2179 if (child != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002180 node = child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002181
Daniel Veillard4c004142003-10-07 11:33:24 +00002182 if (node != NULL) {
2183 if ((node->type == XML_DOCUMENT_NODE) ||
2184 (node->type == XML_HTML_DOCUMENT_NODE)) {
2185 xmlDocPtr doc = (xmlDocPtr) node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002186
Daniel Veillard4c004142003-10-07 11:33:24 +00002187 file = doc->URL;
2188 } else {
2189 /*
2190 * Try to find contextual informations to report
2191 */
2192 if (node->type == XML_ELEMENT_NODE) {
2193 line = (long) node->content;
2194 } else if ((node->prev != NULL) &&
2195 (node->prev->type == XML_ELEMENT_NODE)) {
2196 line = (long) node->prev->content;
2197 } else if ((node->parent != NULL) &&
2198 (node->parent->type == XML_ELEMENT_NODE)) {
2199 line = (long) node->parent->content;
2200 }
2201 if ((node->doc != NULL) && (node->doc->URL != NULL))
2202 file = node->doc->URL;
2203 if (node->name != NULL)
2204 name = node->name;
2205 }
2206 }
2207
Daniel Veillard42f12e92003-03-07 18:32:59 +00002208 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002209
2210 if ((file != NULL) && (line != 0) && (name != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002211 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2212 type, file, line, name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002213 else if ((file != NULL) && (name != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002214 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2215 type, file, name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002216 else if ((file != NULL) && (line != 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00002217 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file,
2218 line);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002219 else if (file != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002220 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002221 else if (name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002222 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002223 else
Daniel Veillard4c004142003-10-07 11:33:24 +00002224 ctxt->error(ctxt->userData, "%s\n", type);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002225}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002226
2227/**
2228 * xmlRelaxNGShowValidError:
2229 * @ctxt: the validation context
2230 * @err: the error number
2231 * @node: the node
2232 * @child: the node child generating the problem.
2233 * @arg1: the first argument
2234 * @arg2: the second argument
2235 *
2236 * Show a validation error.
2237 */
2238static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002239xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2240 xmlRelaxNGValidErr err, xmlNodePtr node,
2241 xmlNodePtr child, const xmlChar * arg1,
2242 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002243{
2244 xmlChar *msg;
2245
2246 if (ctxt->error == NULL)
2247 return;
2248
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002249#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002250 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002251#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002252 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2253 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002254 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002255
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002256 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002257 ctxt->errNo = err;
2258 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2259 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002260 xmlFree(msg);
2261}
2262
2263/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002264 * xmlRelaxNGPopErrors:
2265 * @ctxt: the validation context
2266 * @level: the error level in the stack
2267 *
2268 * pop and discard all errors until the given level is reached
2269 */
2270static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002271xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2272{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002273 int i;
2274 xmlRelaxNGValidErrorPtr err;
2275
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002276#ifdef DEBUG_ERROR
2277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002278 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002279#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002280 for (i = level; i < ctxt->errNr; i++) {
2281 err = &ctxt->errTab[i];
2282 if (err->flags & ERROR_IS_DUP) {
2283 if (err->arg1 != NULL)
2284 xmlFree((xmlChar *) err->arg1);
2285 err->arg1 = NULL;
2286 if (err->arg2 != NULL)
2287 xmlFree((xmlChar *) err->arg2);
2288 err->arg2 = NULL;
2289 err->flags = 0;
2290 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002291 }
2292 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002293 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002294 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002295}
Daniel Veillard4c004142003-10-07 11:33:24 +00002296
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002297/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002298 * xmlRelaxNGDumpValidError:
2299 * @ctxt: the validation context
2300 *
2301 * Show all validation error over a given index.
2302 */
2303static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002304xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2305{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002306 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002307 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002308
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002309#ifdef DEBUG_ERROR
2310 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002311 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002312#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002313 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2314 err = &ctxt->errTab[i];
2315 if (k < MAX_ERROR) {
2316 for (j = 0; j < i; j++) {
2317 dup = &ctxt->errTab[j];
2318 if ((err->err == dup->err) && (err->node == dup->node) &&
2319 (xmlStrEqual(err->arg1, dup->arg1)) &&
2320 (xmlStrEqual(err->arg2, dup->arg2))) {
2321 goto skip;
2322 }
2323 }
2324 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2325 err->arg1, err->arg2);
2326 k++;
2327 }
2328 skip:
2329 if (err->flags & ERROR_IS_DUP) {
2330 if (err->arg1 != NULL)
2331 xmlFree((xmlChar *) err->arg1);
2332 err->arg1 = NULL;
2333 if (err->arg2 != NULL)
2334 xmlFree((xmlChar *) err->arg2);
2335 err->arg2 = NULL;
2336 err->flags = 0;
2337 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002338 }
2339 ctxt->errNr = 0;
2340}
Daniel Veillard4c004142003-10-07 11:33:24 +00002341
Daniel Veillard42f12e92003-03-07 18:32:59 +00002342/**
2343 * xmlRelaxNGAddValidError:
2344 * @ctxt: the validation context
2345 * @err: the error number
2346 * @arg1: the first argument
2347 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002348 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002349 *
2350 * Register a validation error, either generating it if it's sure
2351 * or stacking it for later handling if unsure.
2352 */
2353static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002354xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2355 xmlRelaxNGValidErr err, const xmlChar * arg1,
2356 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002357{
2358 if ((ctxt == NULL) || (ctxt->error == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002359 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002360
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002361#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002362 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002363#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002364 /*
2365 * generate the error directly
2366 */
2367 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002368 xmlNodePtr node, seq;
2369
2370 /*
2371 * Flush first any stacked error which might be the
2372 * real cause of the problem.
2373 */
2374 if (ctxt->errNr != 0)
2375 xmlRelaxNGDumpValidError(ctxt);
2376 if (ctxt->state != NULL) {
2377 node = ctxt->state->node;
2378 seq = ctxt->state->seq;
2379 } else {
2380 node = seq = NULL;
2381 }
2382 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002383 }
2384 /*
2385 * Stack the error for later processing if needed
2386 */
2387 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002388 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002389 }
2390}
2391
Daniel Veillard6eadf632003-01-23 18:29:16 +00002392
2393/************************************************************************
2394 * *
2395 * Type library hooks *
2396 * *
2397 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002398static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002399 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002400
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002401/**
2402 * xmlRelaxNGSchemaTypeHave:
2403 * @data: data needed for the library
2404 * @type: the type name
2405 *
2406 * Check if the given type is provided by
2407 * the W3C XMLSchema Datatype library.
2408 *
2409 * Returns 1 if yes, 0 if no and -1 in case of error.
2410 */
2411static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002412xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2413{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002414 xmlSchemaTypePtr typ;
2415
2416 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002417 return (-1);
2418 typ = xmlSchemaGetPredefinedType(type,
2419 BAD_CAST
2420 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002421 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002422 return (0);
2423 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002424}
2425
2426/**
2427 * xmlRelaxNGSchemaTypeCheck:
2428 * @data: data needed for the library
2429 * @type: the type name
2430 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002431 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002432 *
2433 * Check if the given type and value are validated by
2434 * the W3C XMLSchema Datatype library.
2435 *
2436 * Returns 1 if yes, 0 if no and -1 in case of error.
2437 */
2438static int
2439xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002440 const xmlChar * type,
2441 const xmlChar * value,
2442 void **result, xmlNodePtr node)
2443{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002444 xmlSchemaTypePtr typ;
2445 int ret;
2446
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002447 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002448 return (-1);
2449 typ = xmlSchemaGetPredefinedType(type,
2450 BAD_CAST
2451 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002452 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002453 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002454 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002455 (xmlSchemaValPtr *) result, node);
2456 if (ret == 2) /* special ID error code */
2457 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002458 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002459 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002460 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002461 return (0);
2462 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002463}
2464
2465/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002466 * xmlRelaxNGSchemaFacetCheck:
2467 * @data: data needed for the library
2468 * @type: the type name
2469 * @facet: the facet name
2470 * @val: the facet value
2471 * @strval: the string value
2472 * @value: the value to check
2473 *
2474 * Function provided by a type library to check a value facet
2475 *
2476 * Returns 1 if yes, 0 if no and -1 in case of error.
2477 */
2478static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002479xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2480 const xmlChar * type, const xmlChar * facetname,
2481 const xmlChar * val, const xmlChar * strval,
2482 void *value)
2483{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002484 xmlSchemaFacetPtr facet;
2485 xmlSchemaTypePtr typ;
2486 int ret;
2487
2488 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002489 return (-1);
2490 typ = xmlSchemaGetPredefinedType(type,
2491 BAD_CAST
2492 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002493 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002494 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002495
2496 facet = xmlSchemaNewFacet();
2497 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002498 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002499
Daniel Veillard4c004142003-10-07 11:33:24 +00002500 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002501 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002502 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002503 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002504 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002505 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002506 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002507 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002508 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002509 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002510 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002511 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002512 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002513 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002514 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002515 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002516 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002517 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002518 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002519 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002520 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002521 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2522 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2523 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2524 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002525 xmlSchemaFreeFacet(facet);
2526 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002527 }
2528 facet->value = xmlStrdup(val);
2529 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2530 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002531 xmlSchemaFreeFacet(facet);
2532 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002533 }
2534 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2535 xmlSchemaFreeFacet(facet);
2536 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002537 return (-1);
2538 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002539}
2540
2541/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002542 * xmlRelaxNGSchemaFreeValue:
2543 * @data: data needed for the library
2544 * @value: the value to free
2545 *
2546 * Function provided by a type library to free a Schemas value
2547 *
2548 * Returns 1 if yes, 0 if no and -1 in case of error.
2549 */
2550static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002551xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2552{
Daniel Veillard80b19092003-03-28 13:29:53 +00002553 xmlSchemaFreeValue(value);
2554}
2555
2556/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002557 * xmlRelaxNGSchemaTypeCompare:
2558 * @data: data needed for the library
2559 * @type: the type name
2560 * @value1: the first value
2561 * @value2: the second value
2562 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002563 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002564 * Datatype library.
2565 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002566 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002567 */
2568static int
2569xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002570 const xmlChar * type,
2571 const xmlChar * value1,
2572 xmlNodePtr ctxt1,
2573 void *comp1,
2574 const xmlChar * value2, xmlNodePtr ctxt2)
2575{
Daniel Veillard80b19092003-03-28 13:29:53 +00002576 int ret;
2577 xmlSchemaTypePtr typ;
2578 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2579
2580 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002581 return (-1);
2582 typ = xmlSchemaGetPredefinedType(type,
2583 BAD_CAST
2584 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002585 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002586 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002587 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002588 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2589 if (ret != 0)
2590 return (-1);
2591 if (res1 == NULL)
2592 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002593 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002594 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002595 }
2596 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002597 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002598 xmlSchemaFreeValue(res1);
2599 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002600 }
2601 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002602 xmlSchemaFreeValue(res1);
2603 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002604 }
2605 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002606 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002607 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002608 xmlSchemaFreeValue(res2);
2609 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002610 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002611 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002612 return (1);
2613 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002614}
Daniel Veillard4c004142003-10-07 11:33:24 +00002615
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002616/**
2617 * xmlRelaxNGDefaultTypeHave:
2618 * @data: data needed for the library
2619 * @type: the type name
2620 *
2621 * Check if the given type is provided by
2622 * the default datatype library.
2623 *
2624 * Returns 1 if yes, 0 if no and -1 in case of error.
2625 */
2626static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002627xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2628 const xmlChar * type)
2629{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002630 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002631 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002632 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002633 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002634 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002635 return (1);
2636 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002637}
2638
2639/**
2640 * xmlRelaxNGDefaultTypeCheck:
2641 * @data: data needed for the library
2642 * @type: the type name
2643 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002644 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002645 *
2646 * Check if the given type and value are validated by
2647 * the default datatype library.
2648 *
2649 * Returns 1 if yes, 0 if no and -1 in case of error.
2650 */
2651static int
2652xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002653 const xmlChar * type ATTRIBUTE_UNUSED,
2654 const xmlChar * value ATTRIBUTE_UNUSED,
2655 void **result ATTRIBUTE_UNUSED,
2656 xmlNodePtr node ATTRIBUTE_UNUSED)
2657{
Daniel Veillardd4310742003-02-18 21:12:46 +00002658 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002659 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002660 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002661 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002662 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002663 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002664 }
2665
Daniel Veillard4c004142003-10-07 11:33:24 +00002666 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002667}
2668
2669/**
2670 * xmlRelaxNGDefaultTypeCompare:
2671 * @data: data needed for the library
2672 * @type: the type name
2673 * @value1: the first value
2674 * @value2: the second value
2675 *
2676 * Compare two values accordingly a type from the default
2677 * datatype library.
2678 *
2679 * Returns 1 if yes, 0 if no and -1 in case of error.
2680 */
2681static int
2682xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002683 const xmlChar * type,
2684 const xmlChar * value1,
2685 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2686 void *comp1 ATTRIBUTE_UNUSED,
2687 const xmlChar * value2,
2688 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2689{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002690 int ret = -1;
2691
2692 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002693 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002694 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002695 if (!xmlStrEqual(value1, value2)) {
2696 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002697
Daniel Veillard4c004142003-10-07 11:33:24 +00002698 /*
2699 * TODO: trivial optimizations are possible by
2700 * computing at compile-time
2701 */
2702 nval = xmlRelaxNGNormalize(NULL, value1);
2703 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002704
Daniel Veillard4c004142003-10-07 11:33:24 +00002705 if ((nval == NULL) || (nvalue == NULL))
2706 ret = -1;
2707 else if (xmlStrEqual(nval, nvalue))
2708 ret = 1;
2709 else
2710 ret = 0;
2711 if (nval != NULL)
2712 xmlFree(nval);
2713 if (nvalue != NULL)
2714 xmlFree(nvalue);
2715 } else
2716 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002717 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002718 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002719}
Daniel Veillard4c004142003-10-07 11:33:24 +00002720
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002721static int xmlRelaxNGTypeInitialized = 0;
2722static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2723
2724/**
2725 * xmlRelaxNGFreeTypeLibrary:
2726 * @lib: the type library structure
2727 * @namespace: the URI bound to the library
2728 *
2729 * Free the structure associated to the type library
2730 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002731static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002732xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002733 const xmlChar * namespace ATTRIBUTE_UNUSED)
2734{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002735 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002736 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002737 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002738 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002739 xmlFree(lib);
2740}
2741
2742/**
2743 * xmlRelaxNGRegisterTypeLibrary:
2744 * @namespace: the URI bound to the library
2745 * @data: data associated to the library
2746 * @have: the provide function
2747 * @check: the checking function
2748 * @comp: the comparison function
2749 *
2750 * Register a new type library
2751 *
2752 * Returns 0 in case of success and -1 in case of error.
2753 */
2754static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002755xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2756 xmlRelaxNGTypeHave have,
2757 xmlRelaxNGTypeCheck check,
2758 xmlRelaxNGTypeCompare comp,
2759 xmlRelaxNGFacetCheck facet,
2760 xmlRelaxNGTypeFree freef)
2761{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002762 xmlRelaxNGTypeLibraryPtr lib;
2763 int ret;
2764
2765 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002766 (check == NULL) || (comp == NULL))
2767 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002768 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002769 xmlGenericError(xmlGenericErrorContext,
2770 "Relax-NG types library '%s' already registered\n",
2771 namespace);
2772 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002773 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002774 lib =
2775 (xmlRelaxNGTypeLibraryPtr)
2776 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002777 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002778 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002779 return (-1);
2780 }
2781 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2782 lib->namespace = xmlStrdup(namespace);
2783 lib->data = data;
2784 lib->have = have;
2785 lib->comp = comp;
2786 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002787 lib->facet = facet;
2788 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002789 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2790 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002791 xmlGenericError(xmlGenericErrorContext,
2792 "Relax-NG types library failed to register '%s'\n",
2793 namespace);
2794 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2795 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002796 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002797 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002798}
2799
2800/**
2801 * xmlRelaxNGInitTypes:
2802 *
2803 * Initilize the default type libraries.
2804 *
2805 * Returns 0 in case of success and -1 in case of error.
2806 */
2807static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002808xmlRelaxNGInitTypes(void)
2809{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002810 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002811 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002812 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2813 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002814 xmlGenericError(xmlGenericErrorContext,
2815 "Failed to allocate sh table for Relax-NG types\n");
2816 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002817 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002818 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2819 "http://www.w3.org/2001/XMLSchema-datatypes",
2820 NULL, xmlRelaxNGSchemaTypeHave,
2821 xmlRelaxNGSchemaTypeCheck,
2822 xmlRelaxNGSchemaTypeCompare,
2823 xmlRelaxNGSchemaFacetCheck,
2824 xmlRelaxNGSchemaFreeValue);
2825 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2826 xmlRelaxNGDefaultTypeHave,
2827 xmlRelaxNGDefaultTypeCheck,
2828 xmlRelaxNGDefaultTypeCompare, NULL,
2829 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002830 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002831 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002832}
2833
2834/**
2835 * xmlRelaxNGCleanupTypes:
2836 *
2837 * Cleanup the default Schemas type library associated to RelaxNG
2838 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002839void
2840xmlRelaxNGCleanupTypes(void)
2841{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002842 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002843 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002844 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002845 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002846 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002847 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002848}
2849
2850/************************************************************************
2851 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002852 * Compiling element content into regexp *
2853 * *
2854 * Sometime the element content can be compiled into a pure regexp, *
2855 * This allows a faster execution and streamability at that level *
2856 * *
2857 ************************************************************************/
2858
Daniel Veillard52b48c72003-04-13 19:53:42 +00002859static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2860 xmlRelaxNGDefinePtr def);
2861
Daniel Veillard952379b2003-03-17 15:37:12 +00002862/**
2863 * xmlRelaxNGIsCompileable:
2864 * @define: the definition to check
2865 *
2866 * Check if a definition is nullable.
2867 *
2868 * Returns 1 if yes, 0 if no and -1 in case of error
2869 */
2870static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002871xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2872{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002873 int ret = -1;
2874
Daniel Veillard952379b2003-03-17 15:37:12 +00002875 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002876 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002877 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002878 if ((def->type != XML_RELAXNG_ELEMENT) &&
2879 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002880 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002881 if ((def->type != XML_RELAXNG_ELEMENT) &&
2882 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002883 return (0);
2884 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002885 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002886 ret = xmlRelaxNGIsCompileable(def->content);
2887 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002888 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002889 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002890 ret = 1;
2891 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002892 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002893 /*
2894 * Check if the element content is compileable
2895 */
2896 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2897 ((def->dflags & IS_COMPILABLE) == 0)) {
2898 xmlRelaxNGDefinePtr list;
2899
2900 list = def->content;
2901 while (list != NULL) {
2902 ret = xmlRelaxNGIsCompileable(list);
2903 if (ret != 1)
2904 break;
2905 list = list->next;
2906 }
2907 if (ret == 0)
2908 def->dflags |= IS_NOT_COMPILABLE;
2909 if (ret == 1)
2910 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002911#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002912 if (ret == 1) {
2913 xmlGenericError(xmlGenericErrorContext,
2914 "element content for %s is compilable\n",
2915 def->name);
2916 } else if (ret == 0) {
2917 xmlGenericError(xmlGenericErrorContext,
2918 "element content for %s is not compilable\n",
2919 def->name);
2920 } else {
2921 xmlGenericError(xmlGenericErrorContext,
2922 "Problem in RelaxNGIsCompileable for element %s\n",
2923 def->name);
2924 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002925#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002926 }
2927 /*
2928 * All elements return a compileable status unless they
2929 * are generic like anyName
2930 */
2931 if ((def->nameClass != NULL) || (def->name == NULL))
2932 ret = 0;
2933 else
2934 ret = 1;
2935 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002936 case XML_RELAXNG_REF:
2937 case XML_RELAXNG_EXTERNALREF:
2938 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002939 if (def->depth == -20) {
2940 return (1);
2941 } else {
2942 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002943
Daniel Veillard4c004142003-10-07 11:33:24 +00002944 def->depth = -20;
2945 list = def->content;
2946 while (list != NULL) {
2947 ret = xmlRelaxNGIsCompileable(list);
2948 if (ret != 1)
2949 break;
2950 list = list->next;
2951 }
2952 }
2953 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002954 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002955 case XML_RELAXNG_OPTIONAL:
2956 case XML_RELAXNG_ZEROORMORE:
2957 case XML_RELAXNG_ONEORMORE:
2958 case XML_RELAXNG_CHOICE:
2959 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002960 case XML_RELAXNG_DEF:{
2961 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002962
Daniel Veillard4c004142003-10-07 11:33:24 +00002963 list = def->content;
2964 while (list != NULL) {
2965 ret = xmlRelaxNGIsCompileable(list);
2966 if (ret != 1)
2967 break;
2968 list = list->next;
2969 }
2970 break;
2971 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002972 case XML_RELAXNG_EXCEPT:
2973 case XML_RELAXNG_ATTRIBUTE:
2974 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002975 case XML_RELAXNG_DATATYPE:
2976 case XML_RELAXNG_LIST:
2977 case XML_RELAXNG_PARAM:
2978 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002979 ret = 0;
2980 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002981 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00002982 ret = -1;
2983 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002984 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002985 if (ret == 0)
2986 def->dflags |= IS_NOT_COMPILABLE;
2987 if (ret == 1)
2988 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002989#ifdef DEBUG_COMPILE
2990 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002991 xmlGenericError(xmlGenericErrorContext,
2992 "RelaxNGIsCompileable %s : true\n",
2993 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002994 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002995 xmlGenericError(xmlGenericErrorContext,
2996 "RelaxNGIsCompileable %s : false\n",
2997 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002998 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002999 xmlGenericError(xmlGenericErrorContext,
3000 "Problem in RelaxNGIsCompileable %s\n",
3001 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00003002 }
3003#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003004 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003005}
3006
3007/**
3008 * xmlRelaxNGCompile:
3009 * ctxt: the RelaxNG parser context
3010 * @define: the definition tree to compile
3011 *
3012 * Compile the set of definitions, it works recursively, till the
3013 * element boundaries, where it tries to compile the content if possible
3014 *
3015 * Returns 0 if success and -1 in case of error
3016 */
3017static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003018xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3019{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003020 int ret = 0;
3021 xmlRelaxNGDefinePtr list;
3022
Daniel Veillard4c004142003-10-07 11:33:24 +00003023 if ((ctxt == NULL) || (def == NULL))
3024 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003025
Daniel Veillard4c004142003-10-07 11:33:24 +00003026 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003027 case XML_RELAXNG_START:
3028 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003029 xmlAutomataPtr oldam = ctxt->am;
3030 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003031
3032 def->depth = -25;
3033
Daniel Veillard4c004142003-10-07 11:33:24 +00003034 list = def->content;
3035 ctxt->am = xmlNewAutomata();
3036 if (ctxt->am == NULL)
3037 return (-1);
3038 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3039 while (list != NULL) {
3040 xmlRelaxNGCompile(ctxt, list);
3041 list = list->next;
3042 }
3043 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3044 def->contModel = xmlAutomataCompile(ctxt->am);
3045 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003046
Daniel Veillard4c004142003-10-07 11:33:24 +00003047 xmlFreeAutomata(ctxt->am);
3048 ctxt->state = oldstate;
3049 ctxt->am = oldam;
3050 }
3051 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003052 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003053 if ((ctxt->am != NULL) && (def->name != NULL)) {
3054 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3055 ctxt->state, NULL,
3056 def->name, def->ns,
3057 def);
3058 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003059 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003060 xmlAutomataPtr oldam = ctxt->am;
3061 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003062
3063 def->depth = -25;
3064
Daniel Veillard4c004142003-10-07 11:33:24 +00003065 list = def->content;
3066 ctxt->am = xmlNewAutomata();
3067 if (ctxt->am == NULL)
3068 return (-1);
3069 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3070 while (list != NULL) {
3071 xmlRelaxNGCompile(ctxt, list);
3072 list = list->next;
3073 }
3074 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3075 def->contModel = xmlAutomataCompile(ctxt->am);
3076 if (!xmlRegexpIsDeterminist(def->contModel)) {
3077 /*
3078 * we can only use the automata if it is determinist
3079 */
3080 xmlRegFreeRegexp(def->contModel);
3081 def->contModel = NULL;
3082 }
3083 xmlFreeAutomata(ctxt->am);
3084 ctxt->state = oldstate;
3085 ctxt->am = oldam;
3086 } else {
3087 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003088
Daniel Veillard4c004142003-10-07 11:33:24 +00003089 /*
3090 * we can't build the content model for this element content
3091 * but it still might be possible to build it for some of its
3092 * children, recurse.
3093 */
3094 ret = xmlRelaxNGTryCompile(ctxt, def);
3095 ctxt->am = oldam;
3096 }
3097 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003098 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003099 ret = xmlRelaxNGCompile(ctxt, def->content);
3100 break;
3101 case XML_RELAXNG_OPTIONAL:{
3102 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003103
Daniel Veillard4c004142003-10-07 11:33:24 +00003104 xmlRelaxNGCompile(ctxt, def->content);
3105 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3106 break;
3107 }
3108 case XML_RELAXNG_ZEROORMORE:{
3109 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003110
Daniel Veillard4c004142003-10-07 11:33:24 +00003111 ctxt->state =
3112 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3113 oldstate = ctxt->state;
3114 list = def->content;
3115 while (list != NULL) {
3116 xmlRelaxNGCompile(ctxt, list);
3117 list = list->next;
3118 }
3119 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3120 ctxt->state =
3121 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3122 break;
3123 }
3124 case XML_RELAXNG_ONEORMORE:{
3125 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003126
Daniel Veillard4c004142003-10-07 11:33:24 +00003127 list = def->content;
3128 while (list != NULL) {
3129 xmlRelaxNGCompile(ctxt, list);
3130 list = list->next;
3131 }
3132 oldstate = ctxt->state;
3133 list = def->content;
3134 while (list != NULL) {
3135 xmlRelaxNGCompile(ctxt, list);
3136 list = list->next;
3137 }
3138 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3139 ctxt->state =
3140 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3141 break;
3142 }
3143 case XML_RELAXNG_CHOICE:{
3144 xmlAutomataStatePtr target = NULL;
3145 xmlAutomataStatePtr oldstate = ctxt->state;
3146
3147 list = def->content;
3148 while (list != NULL) {
3149 ctxt->state = oldstate;
3150 ret = xmlRelaxNGCompile(ctxt, list);
3151 if (ret != 0)
3152 break;
3153 if (target == NULL)
3154 target = ctxt->state;
3155 else {
3156 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3157 target);
3158 }
3159 list = list->next;
3160 }
3161 ctxt->state = target;
3162
3163 break;
3164 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003165 case XML_RELAXNG_REF:
3166 case XML_RELAXNG_EXTERNALREF:
3167 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003168 case XML_RELAXNG_GROUP:
3169 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003170 list = def->content;
3171 while (list != NULL) {
3172 ret = xmlRelaxNGCompile(ctxt, list);
3173 if (ret != 0)
3174 break;
3175 list = list->next;
3176 }
3177 break;
3178 case XML_RELAXNG_TEXT:{
3179 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003180
Daniel Veillard4c004142003-10-07 11:33:24 +00003181 ctxt->state =
3182 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3183 oldstate = ctxt->state;
3184 xmlRelaxNGCompile(ctxt, def->content);
3185 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3186 ctxt->state, BAD_CAST "#text",
3187 NULL);
3188 ctxt->state =
3189 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3190 break;
3191 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003192 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003193 ctxt->state =
3194 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3195 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003196 case XML_RELAXNG_EXCEPT:
3197 case XML_RELAXNG_ATTRIBUTE:
3198 case XML_RELAXNG_INTERLEAVE:
3199 case XML_RELAXNG_NOT_ALLOWED:
3200 case XML_RELAXNG_DATATYPE:
3201 case XML_RELAXNG_LIST:
3202 case XML_RELAXNG_PARAM:
3203 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003204 /* This should not happen and generate an internal error */
3205 fprintf(stderr, "RNG internal error trying to compile %s\n",
3206 xmlRelaxNGDefName(def));
3207 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003208 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003209 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003210}
3211
3212/**
3213 * xmlRelaxNGTryCompile:
3214 * ctxt: the RelaxNG parser context
3215 * @define: the definition tree to compile
3216 *
3217 * Try to compile the set of definitions, it works recursively,
3218 * possibly ignoring parts which cannot be compiled.
3219 *
3220 * Returns 0 if success and -1 in case of error
3221 */
3222static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003223xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3224{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003225 int ret = 0;
3226 xmlRelaxNGDefinePtr list;
3227
Daniel Veillard4c004142003-10-07 11:33:24 +00003228 if ((ctxt == NULL) || (def == NULL))
3229 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003230
3231 if ((def->type == XML_RELAXNG_START) ||
3232 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003233 ret = xmlRelaxNGIsCompileable(def);
3234 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3235 ctxt->am = NULL;
3236 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003237#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003238 if (ret == 0) {
3239 if (def->type == XML_RELAXNG_START)
3240 xmlGenericError(xmlGenericErrorContext,
3241 "compiled the start\n");
3242 else
3243 xmlGenericError(xmlGenericErrorContext,
3244 "compiled element %s\n", def->name);
3245 } else {
3246 if (def->type == XML_RELAXNG_START)
3247 xmlGenericError(xmlGenericErrorContext,
3248 "failed to compile the start\n");
3249 else
3250 xmlGenericError(xmlGenericErrorContext,
3251 "failed to compile element %s\n",
3252 def->name);
3253 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003254#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003255 return (ret);
3256 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003257 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003258 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003259 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003260 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3261 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003262 case XML_RELAXNG_TEXT:
3263 case XML_RELAXNG_DATATYPE:
3264 case XML_RELAXNG_LIST:
3265 case XML_RELAXNG_PARAM:
3266 case XML_RELAXNG_VALUE:
3267 case XML_RELAXNG_EMPTY:
3268 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003269 ret = 0;
3270 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003271 case XML_RELAXNG_OPTIONAL:
3272 case XML_RELAXNG_ZEROORMORE:
3273 case XML_RELAXNG_ONEORMORE:
3274 case XML_RELAXNG_CHOICE:
3275 case XML_RELAXNG_GROUP:
3276 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003277 case XML_RELAXNG_START:
3278 case XML_RELAXNG_REF:
3279 case XML_RELAXNG_EXTERNALREF:
3280 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003281 list = def->content;
3282 while (list != NULL) {
3283 ret = xmlRelaxNGTryCompile(ctxt, list);
3284 if (ret != 0)
3285 break;
3286 list = list->next;
3287 }
3288 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003289 case XML_RELAXNG_EXCEPT:
3290 case XML_RELAXNG_ATTRIBUTE:
3291 case XML_RELAXNG_INTERLEAVE:
3292 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003293 ret = 0;
3294 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003295 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003296 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003297}
3298
3299/************************************************************************
3300 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003301 * Parsing functions *
3302 * *
3303 ************************************************************************/
3304
Daniel Veillard4c004142003-10-07 11:33:24 +00003305static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3306 ctxt, xmlNodePtr node);
3307static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3308 ctxt, xmlNodePtr node);
3309static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3310 ctxt, xmlNodePtr nodes,
3311 int group);
3312static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3313 ctxt, xmlNodePtr node);
3314static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3315 xmlNodePtr node);
3316static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3317 xmlNodePtr nodes);
3318static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3319 ctxt, xmlNodePtr node,
3320 xmlRelaxNGDefinePtr
3321 def);
3322static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3323 ctxt, xmlNodePtr nodes);
3324static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3325 xmlRelaxNGDefinePtr define,
3326 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003327
3328
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003329#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003330
3331/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003332 * xmlRelaxNGIsNullable:
3333 * @define: the definition to verify
3334 *
3335 * Check if a definition is nullable.
3336 *
3337 * Returns 1 if yes, 0 if no and -1 in case of error
3338 */
3339static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003340xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3341{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003342 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003343
Daniel Veillardfd573f12003-03-16 17:52:32 +00003344 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003345 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003346
Daniel Veillarde063f482003-03-21 16:53:17 +00003347 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003348 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003349 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003350 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003351 switch (define->type) {
3352 case XML_RELAXNG_EMPTY:
3353 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003354 ret = 1;
3355 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003356 case XML_RELAXNG_NOOP:
3357 case XML_RELAXNG_DEF:
3358 case XML_RELAXNG_REF:
3359 case XML_RELAXNG_EXTERNALREF:
3360 case XML_RELAXNG_PARENTREF:
3361 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003362 ret = xmlRelaxNGIsNullable(define->content);
3363 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003364 case XML_RELAXNG_EXCEPT:
3365 case XML_RELAXNG_NOT_ALLOWED:
3366 case XML_RELAXNG_ELEMENT:
3367 case XML_RELAXNG_DATATYPE:
3368 case XML_RELAXNG_PARAM:
3369 case XML_RELAXNG_VALUE:
3370 case XML_RELAXNG_LIST:
3371 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003372 ret = 0;
3373 break;
3374 case XML_RELAXNG_CHOICE:{
3375 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003376
Daniel Veillard4c004142003-10-07 11:33:24 +00003377 while (list != NULL) {
3378 ret = xmlRelaxNGIsNullable(list);
3379 if (ret != 0)
3380 goto done;
3381 list = list->next;
3382 }
3383 ret = 0;
3384 break;
3385 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003386 case XML_RELAXNG_START:
3387 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003388 case XML_RELAXNG_GROUP:{
3389 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003390
Daniel Veillard4c004142003-10-07 11:33:24 +00003391 while (list != NULL) {
3392 ret = xmlRelaxNGIsNullable(list);
3393 if (ret != 1)
3394 goto done;
3395 list = list->next;
3396 }
3397 return (1);
3398 }
3399 default:
3400 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003401 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003402 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003403 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003404 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003405 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003406 define->dflags |= IS_NULLABLE;
3407 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003408}
3409
3410/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003411 * xmlRelaxNGIsBlank:
3412 * @str: a string
3413 *
3414 * Check if a string is ignorable c.f. 4.2. Whitespace
3415 *
3416 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3417 */
3418static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003419xmlRelaxNGIsBlank(xmlChar * str)
3420{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003421 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003422 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003423 while (*str != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003424 if (!(IS_BLANK(*str)))
3425 return (0);
3426 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003427 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003428 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003429}
3430
Daniel Veillard6eadf632003-01-23 18:29:16 +00003431/**
3432 * xmlRelaxNGGetDataTypeLibrary:
3433 * @ctxt: a Relax-NG parser context
3434 * @node: the current data or value element
3435 *
3436 * Applies algorithm from 4.3. datatypeLibrary attribute
3437 *
3438 * Returns the datatypeLibary value or NULL if not found
3439 */
3440static xmlChar *
3441xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003442 xmlNodePtr node)
3443{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003444 xmlChar *ret, *escape;
3445
Daniel Veillard6eadf632003-01-23 18:29:16 +00003446 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003447 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3448 if (ret != NULL) {
3449 if (ret[0] == 0) {
3450 xmlFree(ret);
3451 return (NULL);
3452 }
3453 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3454 if (escape == NULL) {
3455 return (ret);
3456 }
3457 xmlFree(ret);
3458 return (escape);
3459 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003460 }
3461 node = node->parent;
3462 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003463 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3464 if (ret != NULL) {
3465 if (ret[0] == 0) {
3466 xmlFree(ret);
3467 return (NULL);
3468 }
3469 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3470 if (escape == NULL) {
3471 return (ret);
3472 }
3473 xmlFree(ret);
3474 return (escape);
3475 }
3476 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003477 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003478 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003479}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003480
3481/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003482 * xmlRelaxNGParseValue:
3483 * @ctxt: a Relax-NG parser context
3484 * @node: the data node.
3485 *
3486 * parse the content of a RelaxNG value node.
3487 *
3488 * Returns the definition pointer or NULL in case of error
3489 */
3490static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003491xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3492{
Daniel Veillardedc91922003-01-26 00:52:04 +00003493 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003494 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003495 xmlChar *type;
3496 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003497 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003498
Daniel Veillardfd573f12003-03-16 17:52:32 +00003499 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003500 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003501 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003502 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003503
3504 type = xmlGetProp(node, BAD_CAST "type");
3505 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003506 xmlRelaxNGNormExtSpace(type);
3507 if (xmlValidateNCName(type, 0)) {
3508 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3509 "value type '%s' is not an NCName\n", type, NULL);
3510 }
3511 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3512 if (library == NULL)
3513 library =
3514 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003515
Daniel Veillard4c004142003-10-07 11:33:24 +00003516 def->name = type;
3517 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003518
Daniel Veillard4c004142003-10-07 11:33:24 +00003519 lib = (xmlRelaxNGTypeLibraryPtr)
3520 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3521 if (lib == NULL) {
3522 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3523 "Use of unregistered type library '%s'\n", library,
3524 NULL);
3525 def->data = NULL;
3526 } else {
3527 def->data = lib;
3528 if (lib->have == NULL) {
3529 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3530 "Internal error with type library '%s': no 'have'\n",
3531 library, NULL);
3532 } else {
3533 success = lib->have(lib->data, def->name);
3534 if (success != 1) {
3535 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3536 "Error type '%s' is not exported by type library '%s'\n",
3537 def->name, library);
3538 }
3539 }
3540 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003541 }
3542 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003543 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003544 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003545 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3546 (node->children->next != NULL)) {
3547 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3548 "Expecting a single text value for <value>content\n",
3549 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003550 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003551 def->value = xmlNodeGetContent(node);
3552 if (def->value == NULL) {
3553 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3554 "Element <value> has no content\n", NULL, NULL);
3555 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3556 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003557
Daniel Veillard4c004142003-10-07 11:33:24 +00003558 success =
3559 lib->check(lib->data, def->name, def->value, &val, node);
3560 if (success != 1) {
3561 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3562 "Value '%s' is not acceptable for type '%s'\n",
3563 def->value, def->name);
3564 } else {
3565 if (val != NULL)
3566 def->attrs = val;
3567 }
3568 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003569 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003570 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003571}
3572
3573/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003574 * xmlRelaxNGParseData:
3575 * @ctxt: a Relax-NG parser context
3576 * @node: the data node.
3577 *
3578 * parse the content of a RelaxNG data node.
3579 *
3580 * Returns the definition pointer or NULL in case of error
3581 */
3582static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003583xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3584{
Daniel Veillard416589a2003-02-17 17:25:42 +00003585 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003586 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003587 xmlRelaxNGTypeLibraryPtr lib;
3588 xmlChar *type;
3589 xmlChar *library;
3590 xmlNodePtr content;
3591 int tmp;
3592
3593 type = xmlGetProp(node, BAD_CAST "type");
3594 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003595 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3596 NULL);
3597 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003598 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003599 xmlRelaxNGNormExtSpace(type);
3600 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003601 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3602 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003603 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003604 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3605 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003606 library =
3607 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003608
Daniel Veillardfd573f12003-03-16 17:52:32 +00003609 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003610 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003611 xmlFree(type);
3612 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003613 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003614 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003615 def->name = type;
3616 def->ns = library;
3617
3618 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003619 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003620 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003621 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3622 "Use of unregistered type library '%s'\n", library,
3623 NULL);
3624 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003625 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003626 def->data = lib;
3627 if (lib->have == NULL) {
3628 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3629 "Internal error with type library '%s': no 'have'\n",
3630 library, NULL);
3631 } else {
3632 tmp = lib->have(lib->data, def->name);
3633 if (tmp != 1) {
3634 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3635 "Error type '%s' is not exported by type library '%s'\n",
3636 def->name, library);
3637 } else
3638 if ((xmlStrEqual
3639 (library,
3640 BAD_CAST
3641 "http://www.w3.org/2001/XMLSchema-datatypes"))
3642 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3643 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3644 ctxt->idref = 1;
3645 }
3646 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003647 }
3648 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003649
3650 /*
3651 * Handle optional params
3652 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003653 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003654 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3655 break;
3656 if (xmlStrEqual(library,
3657 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3658 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3659 "Type library '%s' does not allow type parameters\n",
3660 library, NULL);
3661 content = content->next;
3662 while ((content != NULL) &&
3663 (xmlStrEqual(content->name, BAD_CAST "param")))
3664 content = content->next;
3665 } else {
3666 param = xmlRelaxNGNewDefine(ctxt, node);
3667 if (param != NULL) {
3668 param->type = XML_RELAXNG_PARAM;
3669 param->name = xmlGetProp(content, BAD_CAST "name");
3670 if (param->name == NULL) {
3671 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3672 "param has no name\n", NULL, NULL);
3673 }
3674 param->value = xmlNodeGetContent(content);
3675 if (lastparam == NULL) {
3676 def->attrs = lastparam = param;
3677 } else {
3678 lastparam->next = param;
3679 lastparam = param;
3680 }
3681 if (lib != NULL) {
3682 }
3683 }
3684 content = content->next;
3685 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003686 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003687 /*
3688 * Handle optional except
3689 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003690 if ((content != NULL)
3691 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3692 xmlNodePtr child;
3693 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003694
Daniel Veillard4c004142003-10-07 11:33:24 +00003695 except = xmlRelaxNGNewDefine(ctxt, node);
3696 if (except == NULL) {
3697 return (def);
3698 }
3699 except->type = XML_RELAXNG_EXCEPT;
3700 child = content->children;
3701 if (last == NULL) {
3702 def->content = except;
3703 } else {
3704 last->next = except;
3705 }
3706 if (child == NULL) {
3707 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3708 "except has no content\n", NULL, NULL);
3709 }
3710 while (child != NULL) {
3711 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3712 if (tmp2 != NULL) {
3713 if (last2 == NULL) {
3714 except->content = last2 = tmp2;
3715 } else {
3716 last2->next = tmp2;
3717 last2 = tmp2;
3718 }
3719 }
3720 child = child->next;
3721 }
3722 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003723 }
3724 /*
3725 * Check there is no unhandled data
3726 */
3727 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003728 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3729 "Element data has unexpected content %s\n",
3730 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003731 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003732
Daniel Veillard4c004142003-10-07 11:33:24 +00003733 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003734}
3735
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003736static const xmlChar *invalidName = BAD_CAST "\1";
3737
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003738/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003739 * xmlRelaxNGCompareNameClasses:
3740 * @defs1: the first element/attribute defs
3741 * @defs2: the second element/attribute defs
3742 * @name: the restriction on the name
3743 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003744 *
3745 * Compare the 2 lists of element definitions. The comparison is
3746 * that if both lists do not accept the same QNames, it returns 1
3747 * If the 2 lists can accept the same QName the comparison returns 0
3748 *
3749 * Returns 1 disttinct, 0 if equal
3750 */
3751static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003752xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003753 xmlRelaxNGDefinePtr def2)
3754{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003755 int ret = 1;
3756 xmlNode node;
3757 xmlNs ns;
3758 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003759
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003760 ctxt.flags = FLAGS_IGNORABLE;
3761
Daniel Veillard42f12e92003-03-07 18:32:59 +00003762 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3763
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003764 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003765 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3766 if (def2->type == XML_RELAXNG_TEXT)
3767 return (1);
3768 if (def1->name != NULL) {
3769 node.name = def1->name;
3770 } else {
3771 node.name = invalidName;
3772 }
3773 node.ns = &ns;
3774 if (def1->ns != NULL) {
3775 if (def1->ns[0] == 0) {
3776 node.ns = NULL;
3777 } else {
3778 ns.href = def1->ns;
3779 }
3780 } else {
3781 ns.href = invalidName;
3782 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003783 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003784 if (def1->nameClass != NULL) {
3785 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3786 } else {
3787 ret = 0;
3788 }
3789 } else {
3790 ret = 1;
3791 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003792 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003793 if (def2->type == XML_RELAXNG_TEXT)
3794 return (0);
3795 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003796 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003797 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003798 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003799 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003800 }
3801 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003802 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003803 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003804 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3805 if (def2->name != NULL) {
3806 node.name = def2->name;
3807 } else {
3808 node.name = invalidName;
3809 }
3810 node.ns = &ns;
3811 if (def2->ns != NULL) {
3812 if (def2->ns[0] == 0) {
3813 node.ns = NULL;
3814 } else {
3815 ns.href = def2->ns;
3816 }
3817 } else {
3818 ns.href = invalidName;
3819 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003820 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003821 if (def2->nameClass != NULL) {
3822 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3823 } else {
3824 ret = 0;
3825 }
3826 } else {
3827 ret = 1;
3828 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003829 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003830 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003831 }
3832
Daniel Veillard4c004142003-10-07 11:33:24 +00003833 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003834}
3835
3836/**
3837 * xmlRelaxNGCompareElemDefLists:
3838 * @ctxt: a Relax-NG parser context
3839 * @defs1: the first list of element/attribute defs
3840 * @defs2: the second list of element/attribute defs
3841 *
3842 * Compare the 2 lists of element or attribute definitions. The comparison
3843 * is that if both lists do not accept the same QNames, it returns 1
3844 * If the 2 lists can accept the same QName the comparison returns 0
3845 *
3846 * Returns 1 disttinct, 0 if equal
3847 */
3848static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003849xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3850 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3851 xmlRelaxNGDefinePtr * def2)
3852{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003853 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003854
Daniel Veillard154877e2003-01-30 12:17:05 +00003855 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003856 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003857 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003858 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003859 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003860 while ((*def2) != NULL) {
3861 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3862 return (0);
3863 def2++;
3864 }
3865 def2 = basedef2;
3866 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003867 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003868 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003869}
3870
3871/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003872 * xmlRelaxNGGenerateAttributes:
3873 * @ctxt: a Relax-NG parser context
3874 * @def: the definition definition
3875 *
3876 * Check if the definition can only generate attributes
3877 *
3878 * Returns 1 if yes, 0 if no and -1 in case of error.
3879 */
3880static int
3881xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003882 xmlRelaxNGDefinePtr def)
3883{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003884 xmlRelaxNGDefinePtr parent, cur, tmp;
3885
3886 /*
3887 * Don't run that check in case of error. Infinite recursion
3888 * becomes possible.
3889 */
3890 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003891 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003892
3893 parent = NULL;
3894 cur = def;
3895 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003896 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3897 (cur->type == XML_RELAXNG_TEXT) ||
3898 (cur->type == XML_RELAXNG_DATATYPE) ||
3899 (cur->type == XML_RELAXNG_PARAM) ||
3900 (cur->type == XML_RELAXNG_LIST) ||
3901 (cur->type == XML_RELAXNG_VALUE) ||
3902 (cur->type == XML_RELAXNG_EMPTY))
3903 return (0);
3904 if ((cur->type == XML_RELAXNG_CHOICE) ||
3905 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3906 (cur->type == XML_RELAXNG_GROUP) ||
3907 (cur->type == XML_RELAXNG_ONEORMORE) ||
3908 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3909 (cur->type == XML_RELAXNG_OPTIONAL) ||
3910 (cur->type == XML_RELAXNG_PARENTREF) ||
3911 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3912 (cur->type == XML_RELAXNG_REF) ||
3913 (cur->type == XML_RELAXNG_DEF)) {
3914 if (cur->content != NULL) {
3915 parent = cur;
3916 cur = cur->content;
3917 tmp = cur;
3918 while (tmp != NULL) {
3919 tmp->parent = parent;
3920 tmp = tmp->next;
3921 }
3922 continue;
3923 }
3924 }
3925 if (cur == def)
3926 break;
3927 if (cur->next != NULL) {
3928 cur = cur->next;
3929 continue;
3930 }
3931 do {
3932 cur = cur->parent;
3933 if (cur == NULL)
3934 break;
3935 if (cur == def)
3936 return (1);
3937 if (cur->next != NULL) {
3938 cur = cur->next;
3939 break;
3940 }
3941 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003942 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003943 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003944}
Daniel Veillard4c004142003-10-07 11:33:24 +00003945
Daniel Veillardce192eb2003-04-16 15:58:05 +00003946/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003947 * xmlRelaxNGGetElements:
3948 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003949 * @def: the definition definition
3950 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003951 *
3952 * Compute the list of top elements a definition can generate
3953 *
3954 * Returns a list of elements or NULL if none was found.
3955 */
3956static xmlRelaxNGDefinePtr *
3957xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003958 xmlRelaxNGDefinePtr def, int eora)
3959{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003960 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003961 int len = 0;
3962 int max = 0;
3963
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003964 /*
3965 * Don't run that check in case of error. Infinite recursion
3966 * becomes possible.
3967 */
3968 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003969 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003970
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003971 parent = NULL;
3972 cur = def;
3973 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003974 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3975 (cur->type == XML_RELAXNG_TEXT))) ||
3976 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3977 if (ret == NULL) {
3978 max = 10;
3979 ret = (xmlRelaxNGDefinePtr *)
3980 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3981 if (ret == NULL) {
3982 xmlRngPErrMemory(ctxt, "getting element list\n");
3983 return (NULL);
3984 }
3985 } else if (max <= len) {
3986 max *= 2;
3987 ret =
3988 xmlRealloc(ret,
3989 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3990 if (ret == NULL) {
3991 xmlRngPErrMemory(ctxt, "getting element list\n");
3992 return (NULL);
3993 }
3994 }
3995 ret[len++] = cur;
3996 ret[len] = NULL;
3997 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3998 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3999 (cur->type == XML_RELAXNG_GROUP) ||
4000 (cur->type == XML_RELAXNG_ONEORMORE) ||
4001 (cur->type == XML_RELAXNG_ZEROORMORE) ||
4002 (cur->type == XML_RELAXNG_OPTIONAL) ||
4003 (cur->type == XML_RELAXNG_PARENTREF) ||
4004 (cur->type == XML_RELAXNG_REF) ||
4005 (cur->type == XML_RELAXNG_DEF)) {
4006 /*
4007 * Don't go within elements or attributes or string values.
4008 * Just gather the element top list
4009 */
4010 if (cur->content != NULL) {
4011 parent = cur;
4012 cur = cur->content;
4013 tmp = cur;
4014 while (tmp != NULL) {
4015 tmp->parent = parent;
4016 tmp = tmp->next;
4017 }
4018 continue;
4019 }
4020 }
4021 if (cur == def)
4022 break;
4023 if (cur->next != NULL) {
4024 cur = cur->next;
4025 continue;
4026 }
4027 do {
4028 cur = cur->parent;
4029 if (cur == NULL)
4030 break;
4031 if (cur == def)
4032 return (ret);
4033 if (cur->next != NULL) {
4034 cur = cur->next;
4035 break;
4036 }
4037 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004038 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004039 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004040}
Daniel Veillard4c004142003-10-07 11:33:24 +00004041
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004042/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004043 * xmlRelaxNGCheckChoiceDeterminism:
4044 * @ctxt: a Relax-NG parser context
4045 * @def: the choice definition
4046 *
4047 * Also used to find indeterministic pattern in choice
4048 */
4049static void
4050xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004051 xmlRelaxNGDefinePtr def)
4052{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004053 xmlRelaxNGDefinePtr **list;
4054 xmlRelaxNGDefinePtr cur;
4055 int nbchild = 0, i, j, ret;
4056 int is_nullable = 0;
4057 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004058 xmlHashTablePtr triage = NULL;
4059 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004060
Daniel Veillard4c004142003-10-07 11:33:24 +00004061 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4062 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004063
Daniel Veillarde063f482003-03-21 16:53:17 +00004064 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004065 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004066
Daniel Veillardfd573f12003-03-16 17:52:32 +00004067 /*
4068 * Don't run that check in case of error. Infinite recursion
4069 * becomes possible.
4070 */
4071 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004072 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004073
4074 is_nullable = xmlRelaxNGIsNullable(def);
4075
4076 cur = def->content;
4077 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004078 nbchild++;
4079 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004080 }
4081
4082 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004083 sizeof(xmlRelaxNGDefinePtr
4084 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004085 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004086 xmlRngPErrMemory(ctxt, "building choice\n");
4087 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004088 }
4089 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004090 /*
4091 * a bit strong but safe
4092 */
4093 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004094 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004095 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004096 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004097 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004098 cur = def->content;
4099 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004100 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4101 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4102 is_triable = 0;
4103 } else if (is_triable == 1) {
4104 xmlRelaxNGDefinePtr *tmp;
4105 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004106
Daniel Veillard4c004142003-10-07 11:33:24 +00004107 tmp = list[i];
4108 while ((*tmp != NULL) && (is_triable == 1)) {
4109 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4110 res = xmlHashAddEntry2(triage,
4111 BAD_CAST "#text", NULL,
4112 (void *) cur);
4113 if (res != 0)
4114 is_triable = -1;
4115 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4116 ((*tmp)->name != NULL)) {
4117 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4118 res = xmlHashAddEntry2(triage,
4119 (*tmp)->name, NULL,
4120 (void *) cur);
4121 else
4122 res = xmlHashAddEntry2(triage,
4123 (*tmp)->name, (*tmp)->ns,
4124 (void *) cur);
4125 if (res != 0)
4126 is_triable = -1;
4127 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4128 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4129 res = xmlHashAddEntry2(triage,
4130 BAD_CAST "#any", NULL,
4131 (void *) cur);
4132 else
4133 res = xmlHashAddEntry2(triage,
4134 BAD_CAST "#any", (*tmp)->ns,
4135 (void *) cur);
4136 if (res != 0)
4137 is_triable = -1;
4138 } else {
4139 is_triable = -1;
4140 }
4141 tmp++;
4142 }
4143 }
4144 i++;
4145 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004146 }
4147
Daniel Veillard4c004142003-10-07 11:33:24 +00004148 for (i = 0; i < nbchild; i++) {
4149 if (list[i] == NULL)
4150 continue;
4151 for (j = 0; j < i; j++) {
4152 if (list[j] == NULL)
4153 continue;
4154 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4155 if (ret == 0) {
4156 is_indeterminist = 1;
4157 }
4158 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004159 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004160 for (i = 0; i < nbchild; i++) {
4161 if (list[i] != NULL)
4162 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004163 }
4164
4165 xmlFree(list);
4166 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004167 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004168 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004169 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004170 def->dflags |= IS_TRIABLE;
4171 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004172 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004173 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004174 }
4175 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004176}
4177
4178/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004179 * xmlRelaxNGCheckGroupAttrs:
4180 * @ctxt: a Relax-NG parser context
4181 * @def: the group definition
4182 *
4183 * Detects violations of rule 7.3
4184 */
4185static void
4186xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004187 xmlRelaxNGDefinePtr def)
4188{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004189 xmlRelaxNGDefinePtr **list;
4190 xmlRelaxNGDefinePtr cur;
4191 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004192
4193 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004194 ((def->type != XML_RELAXNG_GROUP) &&
4195 (def->type != XML_RELAXNG_ELEMENT)))
4196 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004197
Daniel Veillarde063f482003-03-21 16:53:17 +00004198 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004199 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004200
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004201 /*
4202 * Don't run that check in case of error. Infinite recursion
4203 * becomes possible.
4204 */
4205 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004206 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004207
Daniel Veillardfd573f12003-03-16 17:52:32 +00004208 cur = def->attrs;
4209 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004210 nbchild++;
4211 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004212 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004213 cur = def->content;
4214 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004215 nbchild++;
4216 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004217 }
4218
4219 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004220 sizeof(xmlRelaxNGDefinePtr
4221 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004222 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004223 xmlRngPErrMemory(ctxt, "building group\n");
4224 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004225 }
4226 i = 0;
4227 cur = def->attrs;
4228 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004229 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4230 i++;
4231 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004232 }
4233 cur = def->content;
4234 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004235 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4236 i++;
4237 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004238 }
4239
Daniel Veillard4c004142003-10-07 11:33:24 +00004240 for (i = 0; i < nbchild; i++) {
4241 if (list[i] == NULL)
4242 continue;
4243 for (j = 0; j < i; j++) {
4244 if (list[j] == NULL)
4245 continue;
4246 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4247 if (ret == 0) {
4248 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4249 "Attributes conflicts in group\n", NULL, NULL);
4250 }
4251 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004252 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004253 for (i = 0; i < nbchild; i++) {
4254 if (list[i] != NULL)
4255 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004256 }
4257
4258 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004259 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004260}
4261
4262/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004263 * xmlRelaxNGComputeInterleaves:
4264 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004265 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004266 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004267 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004268 * A lot of work for preprocessing interleave definitions
4269 * is potentially needed to get a decent execution speed at runtime
4270 * - trying to get a total order on the element nodes generated
4271 * by the interleaves, order the list of interleave definitions
4272 * following that order.
4273 * - if <text/> is used to handle mixed content, it is better to
4274 * flag this in the define and simplify the runtime checking
4275 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004276 */
4277static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004278xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004279 xmlRelaxNGParserCtxtPtr ctxt,
4280 xmlChar * name ATTRIBUTE_UNUSED)
4281{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004282 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004283
Daniel Veillardfd573f12003-03-16 17:52:32 +00004284 xmlRelaxNGPartitionPtr partitions = NULL;
4285 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4286 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004287 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004288 int nbgroups = 0;
4289 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004290 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004291 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004292
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004293 /*
4294 * Don't run that check in case of error. Infinite recursion
4295 * becomes possible.
4296 */
4297 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004298 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004299
Daniel Veillardfd573f12003-03-16 17:52:32 +00004300#ifdef DEBUG_INTERLEAVE
4301 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004302 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004303#endif
4304 cur = def->content;
4305 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004306 nbchild++;
4307 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004308 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004309
Daniel Veillardfd573f12003-03-16 17:52:32 +00004310#ifdef DEBUG_INTERLEAVE
4311 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4312#endif
4313 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004314 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004315 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004316 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004317 cur = def->content;
4318 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004319 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4320 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4321 if (groups[nbgroups] == NULL)
4322 goto error;
4323 if (cur->type == XML_RELAXNG_TEXT)
4324 is_mixed++;
4325 groups[nbgroups]->rule = cur;
4326 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4327 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4328 nbgroups++;
4329 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004330 }
4331#ifdef DEBUG_INTERLEAVE
4332 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4333#endif
4334
4335 /*
4336 * Let's check that all rules makes a partitions according to 7.4
4337 */
4338 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004339 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004340 if (partitions == NULL)
4341 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004342 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004343 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004344 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004345 for (i = 0; i < nbgroups; i++) {
4346 group = groups[i];
4347 for (j = i + 1; j < nbgroups; j++) {
4348 if (groups[j] == NULL)
4349 continue;
4350
4351 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4352 groups[j]->defs);
4353 if (ret == 0) {
4354 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4355 "Element or text conflicts in interleave\n",
4356 NULL, NULL);
4357 }
4358 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4359 groups[j]->attrs);
4360 if (ret == 0) {
4361 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4362 "Attributes conflicts in interleave\n", NULL,
4363 NULL);
4364 }
4365 }
4366 tmp = group->defs;
4367 if ((tmp != NULL) && (*tmp != NULL)) {
4368 while (*tmp != NULL) {
4369 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4370 res = xmlHashAddEntry2(partitions->triage,
4371 BAD_CAST "#text", NULL,
4372 (void *) (long) (i + 1));
4373 if (res != 0)
4374 is_determinist = -1;
4375 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4376 ((*tmp)->name != NULL)) {
4377 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4378 res = xmlHashAddEntry2(partitions->triage,
4379 (*tmp)->name, NULL,
4380 (void *) (long) (i + 1));
4381 else
4382 res = xmlHashAddEntry2(partitions->triage,
4383 (*tmp)->name, (*tmp)->ns,
4384 (void *) (long) (i + 1));
4385 if (res != 0)
4386 is_determinist = -1;
4387 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4388 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4389 res = xmlHashAddEntry2(partitions->triage,
4390 BAD_CAST "#any", NULL,
4391 (void *) (long) (i + 1));
4392 else
4393 res = xmlHashAddEntry2(partitions->triage,
4394 BAD_CAST "#any", (*tmp)->ns,
4395 (void *) (long) (i + 1));
4396 if ((*tmp)->nameClass != NULL)
4397 is_determinist = 2;
4398 if (res != 0)
4399 is_determinist = -1;
4400 } else {
4401 is_determinist = -1;
4402 }
4403 tmp++;
4404 }
4405 } else {
4406 is_determinist = 0;
4407 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004408 }
4409 partitions->groups = groups;
4410
4411 /*
4412 * and save the partition list back in the def
4413 */
4414 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004415 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004416 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004417 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004418 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004419 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004420 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004421 return;
4422
Daniel Veillard4c004142003-10-07 11:33:24 +00004423 error:
4424 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004425 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004426 for (i = 0; i < nbgroups; i++)
4427 if (groups[i] != NULL) {
4428 if (groups[i]->defs != NULL)
4429 xmlFree(groups[i]->defs);
4430 xmlFree(groups[i]);
4431 }
4432 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004433 }
4434 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004435}
4436
4437/**
4438 * xmlRelaxNGParseInterleave:
4439 * @ctxt: a Relax-NG parser context
4440 * @node: the data node.
4441 *
4442 * parse the content of a RelaxNG interleave node.
4443 *
4444 * Returns the definition pointer or NULL in case of error
4445 */
4446static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004447xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4448{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004449 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004450 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004451 xmlNodePtr child;
4452
Daniel Veillardfd573f12003-03-16 17:52:32 +00004453 def = xmlRelaxNGNewDefine(ctxt, node);
4454 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004455 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004456 }
4457 def->type = XML_RELAXNG_INTERLEAVE;
4458
4459 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004460 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004461 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004462 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004463 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004464 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004465
Daniel Veillard4c004142003-10-07 11:33:24 +00004466 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4467 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4468 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4469 "Failed to add %s to hash table\n",
4470 (const xmlChar *) name, NULL);
4471 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004472 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004473 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004474 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004475 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4476 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004477 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004478 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004479 if (IS_RELAXNG(child, "element")) {
4480 cur = xmlRelaxNGParseElement(ctxt, child);
4481 } else {
4482 cur = xmlRelaxNGParsePattern(ctxt, child);
4483 }
4484 if (cur != NULL) {
4485 cur->parent = def;
4486 if (last == NULL) {
4487 def->content = last = cur;
4488 } else {
4489 last->next = cur;
4490 last = cur;
4491 }
4492 }
4493 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004494 }
4495
Daniel Veillard4c004142003-10-07 11:33:24 +00004496 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004497}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004498
4499/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004500 * xmlRelaxNGParseInclude:
4501 * @ctxt: a Relax-NG parser context
4502 * @node: the include node
4503 *
4504 * Integrate the content of an include node in the current grammar
4505 *
4506 * Returns 0 in case of success or -1 in case of error
4507 */
4508static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004509xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4510{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004511 xmlRelaxNGIncludePtr incl;
4512 xmlNodePtr root;
4513 int ret = 0, tmp;
4514
4515 incl = node->_private;
4516 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004517 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4518 "Include node has no data\n", NULL, NULL);
4519 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004520 }
4521 root = xmlDocGetRootElement(incl->doc);
4522 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004523 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4524 NULL, NULL);
4525 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004526 }
4527 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004528 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4529 "Include document root is not a grammar\n", NULL, NULL);
4530 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004531 }
4532
4533 /*
4534 * Merge the definition from both the include and the internal list
4535 */
4536 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004537 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4538 if (tmp != 0)
4539 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004540 }
4541 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004542 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4543 if (tmp != 0)
4544 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004545 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004546 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004547}
4548
4549/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004550 * xmlRelaxNGParseDefine:
4551 * @ctxt: a Relax-NG parser context
4552 * @node: the define node
4553 *
4554 * parse the content of a RelaxNG define element node.
4555 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004556 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004557 */
4558static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004559xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4560{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004561 xmlChar *name;
4562 int ret = 0, tmp;
4563 xmlRelaxNGDefinePtr def;
4564 const xmlChar *olddefine;
4565
4566 name = xmlGetProp(node, BAD_CAST "name");
4567 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004568 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4569 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004570 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004571 xmlRelaxNGNormExtSpace(name);
4572 if (xmlValidateNCName(name, 0)) {
4573 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4574 "define name '%s' is not an NCName\n", name, NULL);
4575 }
4576 def = xmlRelaxNGNewDefine(ctxt, node);
4577 if (def == NULL) {
4578 xmlFree(name);
4579 return (-1);
4580 }
4581 def->type = XML_RELAXNG_DEF;
4582 def->name = name;
4583 if (node->children == NULL) {
4584 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4585 "define has no children\n", NULL, NULL);
4586 } else {
4587 olddefine = ctxt->define;
4588 ctxt->define = name;
4589 def->content =
4590 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4591 ctxt->define = olddefine;
4592 }
4593 if (ctxt->grammar->defs == NULL)
4594 ctxt->grammar->defs = xmlHashCreate(10);
4595 if (ctxt->grammar->defs == NULL) {
4596 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4597 "Could not create definition hash\n", NULL, NULL);
4598 ret = -1;
4599 } else {
4600 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4601 if (tmp < 0) {
4602 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004603
Daniel Veillard4c004142003-10-07 11:33:24 +00004604 prev = xmlHashLookup(ctxt->grammar->defs, name);
4605 if (prev == NULL) {
4606 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4607 "Internal error on define aggregation of %s\n",
4608 name, NULL);
4609 ret = -1;
4610 } else {
4611 while (prev->nextHash != NULL)
4612 prev = prev->nextHash;
4613 prev->nextHash = def;
4614 }
4615 }
4616 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004617 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004618 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004619}
4620
4621/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004622 * xmlRelaxNGProcessExternalRef:
4623 * @ctxt: the parser context
4624 * @node: the externlRef node
4625 *
4626 * Process and compile an externlRef node
4627 *
4628 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4629 */
4630static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004631xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4632{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004633 xmlRelaxNGDocumentPtr docu;
4634 xmlNodePtr root, tmp;
4635 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004636 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004637 xmlRelaxNGDefinePtr def;
4638
4639 docu = node->_private;
4640 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004641 def = xmlRelaxNGNewDefine(ctxt, node);
4642 if (def == NULL)
4643 return (NULL);
4644 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004645
Daniel Veillard4c004142003-10-07 11:33:24 +00004646 if (docu->content == NULL) {
4647 /*
4648 * Then do the parsing for good
4649 */
4650 root = xmlDocGetRootElement(docu->doc);
4651 if (root == NULL) {
4652 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4653 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4654 NULL);
4655 return (NULL);
4656 }
4657 /*
4658 * ns transmission rules
4659 */
4660 ns = xmlGetProp(root, BAD_CAST "ns");
4661 if (ns == NULL) {
4662 tmp = node;
4663 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4664 ns = xmlGetProp(tmp, BAD_CAST "ns");
4665 if (ns != NULL) {
4666 break;
4667 }
4668 tmp = tmp->parent;
4669 }
4670 if (ns != NULL) {
4671 xmlSetProp(root, BAD_CAST "ns", ns);
4672 newNs = 1;
4673 xmlFree(ns);
4674 }
4675 } else {
4676 xmlFree(ns);
4677 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004678
Daniel Veillard4c004142003-10-07 11:33:24 +00004679 /*
4680 * Parsing to get a precompiled schemas.
4681 */
4682 oldflags = ctxt->flags;
4683 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4684 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4685 ctxt->flags = oldflags;
4686 if ((docu->schema != NULL) &&
4687 (docu->schema->topgrammar != NULL)) {
4688 docu->content = docu->schema->topgrammar->start;
4689 }
4690
4691 /*
4692 * the externalRef may be reused in a different ns context
4693 */
4694 if (newNs == 1) {
4695 xmlUnsetProp(root, BAD_CAST "ns");
4696 }
4697 }
4698 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004699 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004700 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004701 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004702 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004703}
4704
4705/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004706 * xmlRelaxNGParsePattern:
4707 * @ctxt: a Relax-NG parser context
4708 * @node: the pattern node.
4709 *
4710 * parse the content of a RelaxNG pattern node.
4711 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004712 * Returns the definition pointer or NULL in case of error or if no
4713 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004714 */
4715static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004716xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4717{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004718 xmlRelaxNGDefinePtr def = NULL;
4719
Daniel Veillardd2298792003-02-14 16:54:11 +00004720 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004721 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004722 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004723 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004724 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004725 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004726 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004727 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004728 def = xmlRelaxNGNewDefine(ctxt, node);
4729 if (def == NULL)
4730 return (NULL);
4731 def->type = XML_RELAXNG_EMPTY;
4732 if (node->children != NULL) {
4733 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4734 "empty: had a child node\n", NULL, NULL);
4735 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004736 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004737 def = xmlRelaxNGNewDefine(ctxt, node);
4738 if (def == NULL)
4739 return (NULL);
4740 def->type = XML_RELAXNG_TEXT;
4741 if (node->children != NULL) {
4742 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4743 "text: had a child node\n", NULL, NULL);
4744 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004745 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004746 def = xmlRelaxNGNewDefine(ctxt, node);
4747 if (def == NULL)
4748 return (NULL);
4749 def->type = XML_RELAXNG_ZEROORMORE;
4750 if (node->children == NULL) {
4751 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4752 "Element %s is empty\n", node->name, NULL);
4753 } else {
4754 def->content =
4755 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4756 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004757 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004758 def = xmlRelaxNGNewDefine(ctxt, node);
4759 if (def == NULL)
4760 return (NULL);
4761 def->type = XML_RELAXNG_ONEORMORE;
4762 if (node->children == NULL) {
4763 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4764 "Element %s is empty\n", node->name, NULL);
4765 } else {
4766 def->content =
4767 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4768 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004769 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004770 def = xmlRelaxNGNewDefine(ctxt, node);
4771 if (def == NULL)
4772 return (NULL);
4773 def->type = XML_RELAXNG_OPTIONAL;
4774 if (node->children == NULL) {
4775 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4776 "Element %s is empty\n", node->name, NULL);
4777 } else {
4778 def->content =
4779 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4780 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004781 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004782 def = xmlRelaxNGNewDefine(ctxt, node);
4783 if (def == NULL)
4784 return (NULL);
4785 def->type = XML_RELAXNG_CHOICE;
4786 if (node->children == NULL) {
4787 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4788 "Element %s is empty\n", node->name, NULL);
4789 } else {
4790 def->content =
4791 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4792 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004793 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004794 def = xmlRelaxNGNewDefine(ctxt, node);
4795 if (def == NULL)
4796 return (NULL);
4797 def->type = XML_RELAXNG_GROUP;
4798 if (node->children == NULL) {
4799 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4800 "Element %s is empty\n", node->name, NULL);
4801 } else {
4802 def->content =
4803 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4804 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004805 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004806 def = xmlRelaxNGNewDefine(ctxt, node);
4807 if (def == NULL)
4808 return (NULL);
4809 def->type = XML_RELAXNG_REF;
4810 def->name = xmlGetProp(node, BAD_CAST "name");
4811 if (def->name == NULL) {
4812 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4813 NULL, NULL);
4814 } else {
4815 xmlRelaxNGNormExtSpace(def->name);
4816 if (xmlValidateNCName(def->name, 0)) {
4817 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4818 "ref name '%s' is not an NCName\n", def->name,
4819 NULL);
4820 }
4821 }
4822 if (node->children != NULL) {
4823 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4824 NULL, NULL);
4825 }
4826 if (ctxt->grammar->refs == NULL)
4827 ctxt->grammar->refs = xmlHashCreate(10);
4828 if (ctxt->grammar->refs == NULL) {
4829 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4830 "Could not create references hash\n", NULL, NULL);
4831 def = NULL;
4832 } else {
4833 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004834
Daniel Veillard4c004142003-10-07 11:33:24 +00004835 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4836 if (tmp < 0) {
4837 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004838
Daniel Veillard4c004142003-10-07 11:33:24 +00004839 prev = (xmlRelaxNGDefinePtr)
4840 xmlHashLookup(ctxt->grammar->refs, def->name);
4841 if (prev == NULL) {
4842 if (def->name != NULL) {
4843 if (ctxt->error != NULL)
4844 ctxt->error(ctxt->userData,
4845 "Error refs definitions '%s'\n",
4846 def->name);
4847 } else {
4848 if (ctxt->error != NULL)
4849 ctxt->error(ctxt->userData,
4850 "Error refs definitions\n");
4851 }
4852 ctxt->nbErrors++;
4853 def = NULL;
4854 } else {
4855 def->nextHash = prev->nextHash;
4856 prev->nextHash = def;
4857 }
4858 }
4859 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004860 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004861 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004862 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004863 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004864 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004865 def = xmlRelaxNGNewDefine(ctxt, node);
4866 if (def == NULL)
4867 return (NULL);
4868 def->type = XML_RELAXNG_LIST;
4869 if (node->children == NULL) {
4870 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4871 "Element %s is empty\n", node->name, NULL);
4872 } else {
4873 def->content =
4874 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4875 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004876 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004877 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004878 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004879 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004880 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004881 def = xmlRelaxNGNewDefine(ctxt, node);
4882 if (def == NULL)
4883 return (NULL);
4884 def->type = XML_RELAXNG_NOT_ALLOWED;
4885 if (node->children != NULL) {
4886 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4887 "xmlRelaxNGParse: notAllowed element is not empty\n",
4888 NULL, NULL);
4889 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004890 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004891 xmlRelaxNGGrammarPtr grammar, old;
4892 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004893
Daniel Veillardc482e262003-02-26 14:48:48 +00004894#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004895 xmlGenericError(xmlGenericErrorContext,
4896 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004897#endif
4898
Daniel Veillard4c004142003-10-07 11:33:24 +00004899 oldparent = ctxt->parentgrammar;
4900 old = ctxt->grammar;
4901 ctxt->parentgrammar = old;
4902 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4903 if (old != NULL) {
4904 ctxt->grammar = old;
4905 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004906#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004907 if (grammar != NULL) {
4908 grammar->next = old->next;
4909 old->next = grammar;
4910 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004911#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004912 }
4913 if (grammar != NULL)
4914 def = grammar->start;
4915 else
4916 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004917 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004918 if (ctxt->parentgrammar == NULL) {
4919 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4920 "Use of parentRef without a parent grammar\n", NULL,
4921 NULL);
4922 return (NULL);
4923 }
4924 def = xmlRelaxNGNewDefine(ctxt, node);
4925 if (def == NULL)
4926 return (NULL);
4927 def->type = XML_RELAXNG_PARENTREF;
4928 def->name = xmlGetProp(node, BAD_CAST "name");
4929 if (def->name == NULL) {
4930 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4931 "parentRef has no name\n", NULL, NULL);
4932 } else {
4933 xmlRelaxNGNormExtSpace(def->name);
4934 if (xmlValidateNCName(def->name, 0)) {
4935 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4936 "parentRef name '%s' is not an NCName\n",
4937 def->name, NULL);
4938 }
4939 }
4940 if (node->children != NULL) {
4941 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4942 "parentRef is not empty\n", NULL, NULL);
4943 }
4944 if (ctxt->parentgrammar->refs == NULL)
4945 ctxt->parentgrammar->refs = xmlHashCreate(10);
4946 if (ctxt->parentgrammar->refs == NULL) {
4947 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4948 "Could not create references hash\n", NULL, NULL);
4949 def = NULL;
4950 } else if (def->name != NULL) {
4951 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004952
Daniel Veillard4c004142003-10-07 11:33:24 +00004953 tmp =
4954 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4955 if (tmp < 0) {
4956 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004957
Daniel Veillard4c004142003-10-07 11:33:24 +00004958 prev = (xmlRelaxNGDefinePtr)
4959 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4960 if (prev == NULL) {
4961 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4962 "Internal error parentRef definitions '%s'\n",
4963 def->name, NULL);
4964 def = NULL;
4965 } else {
4966 def->nextHash = prev->nextHash;
4967 prev->nextHash = def;
4968 }
4969 }
4970 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004971 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004972 if (node->children == NULL) {
4973 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4974 NULL, NULL);
4975 def = NULL;
4976 } else {
4977 def = xmlRelaxNGParseInterleave(ctxt, node);
4978 if (def != NULL) {
4979 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004980
Daniel Veillard4c004142003-10-07 11:33:24 +00004981 if ((def->content != NULL) && (def->content->next != NULL)) {
4982 tmp = xmlRelaxNGNewDefine(ctxt, node);
4983 if (tmp != NULL) {
4984 tmp->type = XML_RELAXNG_GROUP;
4985 tmp->content = def->content;
4986 def->content = tmp;
4987 }
4988 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004989
Daniel Veillard4c004142003-10-07 11:33:24 +00004990 tmp = xmlRelaxNGNewDefine(ctxt, node);
4991 if (tmp == NULL)
4992 return (def);
4993 tmp->type = XML_RELAXNG_TEXT;
4994 tmp->next = def->content;
4995 def->content = tmp;
4996 }
4997 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004998 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004999 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
5000 "Unexpected node %s is not a pattern\n", node->name,
5001 NULL);
5002 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005003 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005004 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005005}
5006
5007/**
5008 * xmlRelaxNGParseAttribute:
5009 * @ctxt: a Relax-NG parser context
5010 * @node: the element node
5011 *
5012 * parse the content of a RelaxNG attribute node.
5013 *
5014 * Returns the definition pointer or NULL in case of error.
5015 */
5016static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005017xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5018{
Daniel Veillardd2298792003-02-14 16:54:11 +00005019 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005020 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005021 int old_flags;
5022
Daniel Veillardfd573f12003-03-16 17:52:32 +00005023 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005024 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005025 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005026 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005027 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005028 child = node->children;
5029 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005030 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5031 "xmlRelaxNGParseattribute: attribute has no children\n",
5032 NULL, NULL);
5033 return (ret);
5034 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005035 old_flags = ctxt->flags;
5036 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005037 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5038 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005039 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005040
Daniel Veillardd2298792003-02-14 16:54:11 +00005041 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005042 cur = xmlRelaxNGParsePattern(ctxt, child);
5043 if (cur != NULL) {
5044 switch (cur->type) {
5045 case XML_RELAXNG_EMPTY:
5046 case XML_RELAXNG_NOT_ALLOWED:
5047 case XML_RELAXNG_TEXT:
5048 case XML_RELAXNG_ELEMENT:
5049 case XML_RELAXNG_DATATYPE:
5050 case XML_RELAXNG_VALUE:
5051 case XML_RELAXNG_LIST:
5052 case XML_RELAXNG_REF:
5053 case XML_RELAXNG_PARENTREF:
5054 case XML_RELAXNG_EXTERNALREF:
5055 case XML_RELAXNG_DEF:
5056 case XML_RELAXNG_ONEORMORE:
5057 case XML_RELAXNG_ZEROORMORE:
5058 case XML_RELAXNG_OPTIONAL:
5059 case XML_RELAXNG_CHOICE:
5060 case XML_RELAXNG_GROUP:
5061 case XML_RELAXNG_INTERLEAVE:
5062 case XML_RELAXNG_ATTRIBUTE:
5063 ret->content = cur;
5064 cur->parent = ret;
5065 break;
5066 case XML_RELAXNG_START:
5067 case XML_RELAXNG_PARAM:
5068 case XML_RELAXNG_EXCEPT:
5069 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5070 "attribute has invalid content\n", NULL,
5071 NULL);
5072 break;
5073 case XML_RELAXNG_NOOP:
5074 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5075 "RNG Internal error, noop found in attribute\n",
5076 NULL, NULL);
5077 break;
5078 }
5079 }
5080 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005081 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005082 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005083 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5084 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005085 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005086 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005087 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005088}
5089
5090/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005091 * xmlRelaxNGParseExceptNameClass:
5092 * @ctxt: a Relax-NG parser context
5093 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005094 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005095 *
5096 * parse the content of a RelaxNG nameClass node.
5097 *
5098 * Returns the definition pointer or NULL in case of error.
5099 */
5100static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005101xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005102 xmlNodePtr node, int attr)
5103{
Daniel Veillard144fae12003-02-03 13:17:57 +00005104 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5105 xmlNodePtr child;
5106
Daniel Veillardd2298792003-02-14 16:54:11 +00005107 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005108 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5109 "Expecting an except node\n", NULL, NULL);
5110 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005111 }
5112 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005113 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5114 "exceptNameClass allows only a single except node\n",
5115 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005116 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005117 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005118 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5119 NULL, NULL);
5120 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005121 }
5122
Daniel Veillardfd573f12003-03-16 17:52:32 +00005123 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005124 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005125 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005126 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005127 child = node->children;
5128 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005129 cur = xmlRelaxNGNewDefine(ctxt, child);
5130 if (cur == NULL)
5131 break;
5132 if (attr)
5133 cur->type = XML_RELAXNG_ATTRIBUTE;
5134 else
5135 cur->type = XML_RELAXNG_ELEMENT;
5136
Daniel Veillard419a7682003-02-03 23:22:49 +00005137 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005138 if (last == NULL) {
5139 ret->content = cur;
5140 } else {
5141 last->next = cur;
5142 }
5143 last = cur;
5144 }
5145 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005146 }
5147
Daniel Veillard4c004142003-10-07 11:33:24 +00005148 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005149}
5150
5151/**
5152 * xmlRelaxNGParseNameClass:
5153 * @ctxt: a Relax-NG parser context
5154 * @node: the nameClass node
5155 * @def: the current definition
5156 *
5157 * parse the content of a RelaxNG nameClass node.
5158 *
5159 * Returns the definition pointer or NULL in case of error.
5160 */
5161static xmlRelaxNGDefinePtr
5162xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005163 xmlRelaxNGDefinePtr def)
5164{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005165 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005166 xmlChar *val;
5167
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005168 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005169 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005170 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005171 if ((def->type != XML_RELAXNG_ELEMENT) &&
5172 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5173 ret = xmlRelaxNGNewDefine(ctxt, node);
5174 if (ret == NULL)
5175 return (NULL);
5176 ret->parent = def;
5177 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5178 ret->type = XML_RELAXNG_ATTRIBUTE;
5179 else
5180 ret->type = XML_RELAXNG_ELEMENT;
5181 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005182 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005183 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005184 val = xmlNodeGetContent(node);
5185 xmlRelaxNGNormExtSpace(val);
5186 if (xmlValidateNCName(val, 0)) {
5187 if (ctxt->error != NULL) {
5188 if (node->parent != NULL)
5189 ctxt->error(ctxt->userData,
5190 "Element %s name '%s' is not an NCName\n",
5191 node->parent->name, val);
5192 else
5193 ctxt->error(ctxt->userData,
5194 "name '%s' is not an NCName\n", val);
5195 }
5196 ctxt->nbErrors++;
5197 }
5198 ret->name = val;
5199 val = xmlGetProp(node, BAD_CAST "ns");
5200 ret->ns = val;
5201 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5202 (val != NULL) &&
5203 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5204 ctxt->error(ctxt->userData,
5205 "Attribute with namespace '%s' is not allowed\n",
5206 val);
5207 ctxt->nbErrors++;
5208 }
5209 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5210 (val != NULL) &&
5211 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5212 ctxt->error(ctxt->userData,
5213 "Attribute with QName 'xmlns' is not allowed\n",
5214 val);
5215 ctxt->nbErrors++;
5216 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005217 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005218 ret->name = NULL;
5219 ret->ns = NULL;
5220 if (node->children != NULL) {
5221 ret->nameClass =
5222 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5223 (def->type ==
5224 XML_RELAXNG_ATTRIBUTE));
5225 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005226 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005227 ret->name = NULL;
5228 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5229 if (ret->ns == NULL) {
5230 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5231 "nsName has no ns attribute\n", NULL, NULL);
5232 }
5233 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5234 (ret->ns != NULL) &&
5235 (xmlStrEqual
5236 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5237 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5238 "Attribute with namespace '%s' is not allowed\n",
5239 ret->ns, NULL);
5240 }
5241 if (node->children != NULL) {
5242 ret->nameClass =
5243 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5244 (def->type ==
5245 XML_RELAXNG_ATTRIBUTE));
5246 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005247 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005248 xmlNodePtr child;
5249 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005250
Daniel Veillard4c004142003-10-07 11:33:24 +00005251 ret = xmlRelaxNGNewDefine(ctxt, node);
5252 if (ret == NULL)
5253 return (NULL);
5254 ret->parent = def;
5255 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005256
Daniel Veillard4c004142003-10-07 11:33:24 +00005257 if (node->children == NULL) {
5258 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5259 "Element choice is empty\n", NULL, NULL);
5260 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005261
Daniel Veillard4c004142003-10-07 11:33:24 +00005262 child = node->children;
5263 while (child != NULL) {
5264 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5265 if (tmp != NULL) {
5266 if (last == NULL) {
5267 last = ret->nameClass = tmp;
5268 } else {
5269 last->next = tmp;
5270 last = tmp;
5271 }
5272 }
5273 child = child->next;
5274 }
5275 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005276 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005277 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5278 "expecting name, anyName, nsName or choice : got %s\n",
5279 node->name, NULL);
5280 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005281 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005282 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005283 if (def->nameClass == NULL) {
5284 def->nameClass = ret;
5285 } else {
5286 tmp = def->nameClass;
5287 while (tmp->next != NULL) {
5288 tmp = tmp->next;
5289 }
5290 tmp->next = ret;
5291 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005292 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005293 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005294}
5295
5296/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005297 * xmlRelaxNGParseElement:
5298 * @ctxt: a Relax-NG parser context
5299 * @node: the element node
5300 *
5301 * parse the content of a RelaxNG element node.
5302 *
5303 * Returns the definition pointer or NULL in case of error.
5304 */
5305static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005306xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5307{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005308 xmlRelaxNGDefinePtr ret, cur, last;
5309 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005310 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005311
Daniel Veillardfd573f12003-03-16 17:52:32 +00005312 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005313 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005314 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005315 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005316 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005317 child = node->children;
5318 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005319 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5320 "xmlRelaxNGParseElement: element has no children\n",
5321 NULL, NULL);
5322 return (ret);
5323 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005324 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5325 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005326 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005327
Daniel Veillard6eadf632003-01-23 18:29:16 +00005328 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005329 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5330 "xmlRelaxNGParseElement: element has no content\n",
5331 NULL, NULL);
5332 return (ret);
5333 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005334 olddefine = ctxt->define;
5335 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005336 last = NULL;
5337 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005338 cur = xmlRelaxNGParsePattern(ctxt, child);
5339 if (cur != NULL) {
5340 cur->parent = ret;
5341 switch (cur->type) {
5342 case XML_RELAXNG_EMPTY:
5343 case XML_RELAXNG_NOT_ALLOWED:
5344 case XML_RELAXNG_TEXT:
5345 case XML_RELAXNG_ELEMENT:
5346 case XML_RELAXNG_DATATYPE:
5347 case XML_RELAXNG_VALUE:
5348 case XML_RELAXNG_LIST:
5349 case XML_RELAXNG_REF:
5350 case XML_RELAXNG_PARENTREF:
5351 case XML_RELAXNG_EXTERNALREF:
5352 case XML_RELAXNG_DEF:
5353 case XML_RELAXNG_ZEROORMORE:
5354 case XML_RELAXNG_ONEORMORE:
5355 case XML_RELAXNG_OPTIONAL:
5356 case XML_RELAXNG_CHOICE:
5357 case XML_RELAXNG_GROUP:
5358 case XML_RELAXNG_INTERLEAVE:
5359 if (last == NULL) {
5360 ret->content = last = cur;
5361 } else {
5362 if ((last->type == XML_RELAXNG_ELEMENT) &&
5363 (ret->content == last)) {
5364 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5365 if (ret->content != NULL) {
5366 ret->content->type = XML_RELAXNG_GROUP;
5367 ret->content->content = last;
5368 } else {
5369 ret->content = last;
5370 }
5371 }
5372 last->next = cur;
5373 last = cur;
5374 }
5375 break;
5376 case XML_RELAXNG_ATTRIBUTE:
5377 cur->next = ret->attrs;
5378 ret->attrs = cur;
5379 break;
5380 case XML_RELAXNG_START:
5381 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5382 "RNG Internal error, start found in element\n",
5383 NULL, NULL);
5384 break;
5385 case XML_RELAXNG_PARAM:
5386 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5387 "RNG Internal error, param found in element\n",
5388 NULL, NULL);
5389 break;
5390 case XML_RELAXNG_EXCEPT:
5391 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5392 "RNG Internal error, except found in element\n",
5393 NULL, NULL);
5394 break;
5395 case XML_RELAXNG_NOOP:
5396 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5397 "RNG Internal error, noop found in element\n",
5398 NULL, NULL);
5399 break;
5400 }
5401 }
5402 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005403 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005404 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005405 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005406}
5407
5408/**
5409 * xmlRelaxNGParsePatterns:
5410 * @ctxt: a Relax-NG parser context
5411 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005412 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005413 *
5414 * parse the content of a RelaxNG start node.
5415 *
5416 * Returns the definition pointer or NULL in case of error.
5417 */
5418static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005419xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005420 int group)
5421{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005422 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005423
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005424 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005425 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005426 if (IS_RELAXNG(nodes, "element")) {
5427 cur = xmlRelaxNGParseElement(ctxt, nodes);
5428 if (def == NULL) {
5429 def = last = cur;
5430 } else {
5431 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5432 (def == last)) {
5433 def = xmlRelaxNGNewDefine(ctxt, nodes);
5434 def->type = XML_RELAXNG_GROUP;
5435 def->content = last;
5436 }
5437 last->next = cur;
5438 last = cur;
5439 }
5440 cur->parent = parent;
5441 } else {
5442 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5443 if (cur != NULL) {
5444 if (def == NULL) {
5445 def = last = cur;
5446 } else {
5447 last->next = cur;
5448 last = cur;
5449 }
5450 }
5451 }
5452 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005453 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005454 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005455}
5456
5457/**
5458 * xmlRelaxNGParseStart:
5459 * @ctxt: a Relax-NG parser context
5460 * @nodes: start children nodes
5461 *
5462 * parse the content of a RelaxNG start node.
5463 *
5464 * Returns 0 in case of success, -1 in case of error
5465 */
5466static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005467xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5468{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005469 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005470 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005471
Daniel Veillardd2298792003-02-14 16:54:11 +00005472 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005473 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5474 NULL, NULL);
5475 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005476 }
5477 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005478 def = xmlRelaxNGNewDefine(ctxt, nodes);
5479 if (def == NULL)
5480 return (-1);
5481 def->type = XML_RELAXNG_EMPTY;
5482 if (nodes->children != NULL) {
5483 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5484 "element empty is not empty\n", NULL, NULL);
5485 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005486 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005487 def = xmlRelaxNGNewDefine(ctxt, nodes);
5488 if (def == NULL)
5489 return (-1);
5490 def->type = XML_RELAXNG_NOT_ALLOWED;
5491 if (nodes->children != NULL) {
5492 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5493 "element notAllowed is not empty\n", NULL, NULL);
5494 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005495 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005496 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005497 }
5498 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005499 last = ctxt->grammar->start;
5500 while (last->next != NULL)
5501 last = last->next;
5502 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005503 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005504 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005505 }
5506 nodes = nodes->next;
5507 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005508 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5509 "start more than one children\n", NULL, NULL);
5510 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005511 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005512 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005513}
5514
5515/**
5516 * xmlRelaxNGParseGrammarContent:
5517 * @ctxt: a Relax-NG parser context
5518 * @nodes: grammar children nodes
5519 *
5520 * parse the content of a RelaxNG grammar node.
5521 *
5522 * Returns 0 in case of success, -1 in case of error
5523 */
5524static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005525xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5526 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005527{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005528 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005529
5530 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005531 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5532 "grammar has no children\n", NULL, NULL);
5533 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005534 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005535 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005536 if (IS_RELAXNG(nodes, "start")) {
5537 if (nodes->children == NULL) {
5538 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5539 "start has no children\n", NULL, NULL);
5540 } else {
5541 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5542 if (tmp != 0)
5543 ret = -1;
5544 }
5545 } else if (IS_RELAXNG(nodes, "define")) {
5546 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5547 if (tmp != 0)
5548 ret = -1;
5549 } else if (IS_RELAXNG(nodes, "include")) {
5550 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5551 if (tmp != 0)
5552 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005553 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005554 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5555 "grammar has unexpected child %s\n", nodes->name,
5556 NULL);
5557 ret = -1;
5558 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005559 nodes = nodes->next;
5560 }
5561 return (ret);
5562}
5563
5564/**
5565 * xmlRelaxNGCheckReference:
5566 * @ref: the ref
5567 * @ctxt: a Relax-NG parser context
5568 * @name: the name associated to the defines
5569 *
5570 * Applies the 4.17. combine attribute rule for all the define
5571 * element of a given grammar using the same name.
5572 */
5573static void
5574xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005575 xmlRelaxNGParserCtxtPtr ctxt,
5576 const xmlChar * name)
5577{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005578 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005579 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005580
5581 grammar = ctxt->grammar;
5582 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005583 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5584 "Internal error: no grammar in CheckReference %s\n",
5585 name, NULL);
5586 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005587 }
5588 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005589 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5590 "Internal error: reference has content in CheckReference %s\n",
5591 name, NULL);
5592 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005593 }
5594 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005595 def = xmlHashLookup(grammar->defs, name);
5596 if (def != NULL) {
5597 cur = ref;
5598 while (cur != NULL) {
5599 cur->content = def;
5600 cur = cur->nextHash;
5601 }
5602 } else {
5603 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5604 "Reference %s has no matching definition\n", name,
5605 NULL);
5606 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005607 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005608 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5609 "Reference %s has no matching definition\n", name,
5610 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005611 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005612}
5613
5614/**
5615 * xmlRelaxNGCheckCombine:
5616 * @define: the define(s) list
5617 * @ctxt: a Relax-NG parser context
5618 * @name: the name associated to the defines
5619 *
5620 * Applies the 4.17. combine attribute rule for all the define
5621 * element of a given grammar using the same name.
5622 */
5623static void
5624xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005625 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5626{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005627 xmlChar *combine;
5628 int choiceOrInterleave = -1;
5629 int missing = 0;
5630 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5631
5632 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005633 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005634 cur = define;
5635 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005636 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5637 if (combine != NULL) {
5638 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5639 if (choiceOrInterleave == -1)
5640 choiceOrInterleave = 1;
5641 else if (choiceOrInterleave == 0) {
5642 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5643 "Defines for %s use both 'choice' and 'interleave'\n",
5644 name, NULL);
5645 }
5646 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5647 if (choiceOrInterleave == -1)
5648 choiceOrInterleave = 0;
5649 else if (choiceOrInterleave == 1) {
5650 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5651 "Defines for %s use both 'choice' and 'interleave'\n",
5652 name, NULL);
5653 }
5654 } else {
5655 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5656 "Defines for %s use unknown combine value '%s''\n",
5657 name, combine);
5658 }
5659 xmlFree(combine);
5660 } else {
5661 if (missing == 0)
5662 missing = 1;
5663 else {
5664 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5665 "Some defines for %s needs the combine attribute\n",
5666 name, NULL);
5667 }
5668 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005669
Daniel Veillard4c004142003-10-07 11:33:24 +00005670 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005671 }
5672#ifdef DEBUG
5673 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005674 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5675 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005676#endif
5677 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005678 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005679 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005680 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005681 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005682 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005683 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005684 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005685 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005686 tmp = define;
5687 last = NULL;
5688 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005689 if (tmp->content != NULL) {
5690 if (tmp->content->next != NULL) {
5691 /*
5692 * we need first to create a wrapper.
5693 */
5694 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5695 if (tmp2 == NULL)
5696 break;
5697 tmp2->type = XML_RELAXNG_GROUP;
5698 tmp2->content = tmp->content;
5699 } else {
5700 tmp2 = tmp->content;
5701 }
5702 if (last == NULL) {
5703 cur->content = tmp2;
5704 } else {
5705 last->next = tmp2;
5706 }
5707 last = tmp2;
5708 }
5709 tmp->content = cur;
5710 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005711 }
5712 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005713 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005714 if (ctxt->interleaves == NULL)
5715 ctxt->interleaves = xmlHashCreate(10);
5716 if (ctxt->interleaves == NULL) {
5717 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5718 "Failed to create interleaves hash table\n", NULL,
5719 NULL);
5720 } else {
5721 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005722
Daniel Veillard4c004142003-10-07 11:33:24 +00005723 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5724 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5725 0) {
5726 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5727 "Failed to add %s to hash table\n",
5728 (const xmlChar *) tmpname, NULL);
5729 }
5730 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005731 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005732}
5733
5734/**
5735 * xmlRelaxNGCombineStart:
5736 * @ctxt: a Relax-NG parser context
5737 * @grammar: the grammar
5738 *
5739 * Applies the 4.17. combine rule for all the start
5740 * element of a given grammar.
5741 */
5742static void
5743xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005744 xmlRelaxNGGrammarPtr grammar)
5745{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005746 xmlRelaxNGDefinePtr starts;
5747 xmlChar *combine;
5748 int choiceOrInterleave = -1;
5749 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005750 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005751
Daniel Veillard2df2de22003-02-17 23:34:33 +00005752 starts = grammar->start;
5753 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005754 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005755 cur = starts;
5756 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005757 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5758 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5759 combine = NULL;
5760 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5761 "Internal error: start element not found\n", NULL,
5762 NULL);
5763 } else {
5764 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5765 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005766
Daniel Veillard4c004142003-10-07 11:33:24 +00005767 if (combine != NULL) {
5768 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5769 if (choiceOrInterleave == -1)
5770 choiceOrInterleave = 1;
5771 else if (choiceOrInterleave == 0) {
5772 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5773 "<start> use both 'choice' and 'interleave'\n",
5774 NULL, NULL);
5775 }
5776 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5777 if (choiceOrInterleave == -1)
5778 choiceOrInterleave = 0;
5779 else if (choiceOrInterleave == 1) {
5780 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5781 "<start> use both 'choice' and 'interleave'\n",
5782 NULL, NULL);
5783 }
5784 } else {
5785 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5786 "<start> uses unknown combine value '%s''\n",
5787 combine, NULL);
5788 }
5789 xmlFree(combine);
5790 } else {
5791 if (missing == 0)
5792 missing = 1;
5793 else {
5794 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5795 "Some <start> element miss the combine attribute\n",
5796 NULL, NULL);
5797 }
5798 }
5799
5800 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005801 }
5802#ifdef DEBUG
5803 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005804 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5805 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005806#endif
5807 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005808 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005809 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005810 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005811 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005812 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005813 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005814 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005815 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005816 cur->content = grammar->start;
5817 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005818 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005819 if (ctxt->interleaves == NULL)
5820 ctxt->interleaves = xmlHashCreate(10);
5821 if (ctxt->interleaves == NULL) {
5822 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5823 "Failed to create interleaves hash table\n", NULL,
5824 NULL);
5825 } else {
5826 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005827
Daniel Veillard4c004142003-10-07 11:33:24 +00005828 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5829 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5830 0) {
5831 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5832 "Failed to add %s to hash table\n",
5833 (const xmlChar *) tmpname, NULL);
5834 }
5835 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005836 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005837}
5838
5839/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005840 * xmlRelaxNGCheckCycles:
5841 * @ctxt: a Relax-NG parser context
5842 * @nodes: grammar children nodes
5843 * @depth: the counter
5844 *
5845 * Check for cycles.
5846 *
5847 * Returns 0 if check passed, and -1 in case of error
5848 */
5849static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005850xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5851 xmlRelaxNGDefinePtr cur, int depth)
5852{
Daniel Veillardd4310742003-02-18 21:12:46 +00005853 int ret = 0;
5854
5855 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005856 if ((cur->type == XML_RELAXNG_REF) ||
5857 (cur->type == XML_RELAXNG_PARENTREF)) {
5858 if (cur->depth == -1) {
5859 cur->depth = depth;
5860 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5861 cur->depth = -2;
5862 } else if (depth == cur->depth) {
5863 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5864 "Detected a cycle in %s references\n",
5865 cur->name, NULL);
5866 return (-1);
5867 }
5868 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5869 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5870 } else {
5871 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5872 }
5873 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005874 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005875 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005876}
5877
5878/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005879 * xmlRelaxNGTryUnlink:
5880 * @ctxt: a Relax-NG parser context
5881 * @cur: the definition to unlink
5882 * @parent: the parent definition
5883 * @prev: the previous sibling definition
5884 *
5885 * Try to unlink a definition. If not possble make it a NOOP
5886 *
5887 * Returns the new prev definition
5888 */
5889static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005890xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5891 xmlRelaxNGDefinePtr cur,
5892 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5893{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005894 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005895 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005896 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005897 if (parent != NULL) {
5898 if (parent->content == cur)
5899 parent->content = cur->next;
5900 else if (parent->attrs == cur)
5901 parent->attrs = cur->next;
5902 else if (parent->nameClass == cur)
5903 parent->nameClass = cur->next;
5904 } else {
5905 cur->type = XML_RELAXNG_NOOP;
5906 prev = cur;
5907 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005908 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005909 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005910}
5911
5912/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005913 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005914 * @ctxt: a Relax-NG parser context
5915 * @nodes: grammar children nodes
5916 *
5917 * Check for simplification of empty and notAllowed
5918 */
5919static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005920xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5921 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5922{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005923 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005924
Daniel Veillardfd573f12003-03-16 17:52:32 +00005925 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005926 if ((cur->type == XML_RELAXNG_REF) ||
5927 (cur->type == XML_RELAXNG_PARENTREF)) {
5928 if (cur->depth != -3) {
5929 cur->depth = -3;
5930 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5931 }
5932 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5933 cur->parent = parent;
5934 if ((parent != NULL) &&
5935 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5936 (parent->type == XML_RELAXNG_LIST) ||
5937 (parent->type == XML_RELAXNG_GROUP) ||
5938 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5939 (parent->type == XML_RELAXNG_ONEORMORE) ||
5940 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5941 parent->type = XML_RELAXNG_NOT_ALLOWED;
5942 break;
5943 }
5944 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5945 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5946 } else
5947 prev = cur;
5948 } else if (cur->type == XML_RELAXNG_EMPTY) {
5949 cur->parent = parent;
5950 if ((parent != NULL) &&
5951 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5952 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5953 parent->type = XML_RELAXNG_EMPTY;
5954 break;
5955 }
5956 if ((parent != NULL) &&
5957 ((parent->type == XML_RELAXNG_GROUP) ||
5958 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5959 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5960 } else
5961 prev = cur;
5962 } else {
5963 cur->parent = parent;
5964 if (cur->content != NULL)
5965 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5966 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5967 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5968 if (cur->nameClass != NULL)
5969 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5970 /*
5971 * On Elements, try to move attribute only generating rules on
5972 * the attrs rules.
5973 */
5974 if (cur->type == XML_RELAXNG_ELEMENT) {
5975 int attronly;
5976 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005977
Daniel Veillard4c004142003-10-07 11:33:24 +00005978 while (cur->content != NULL) {
5979 attronly =
5980 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5981 if (attronly == 1) {
5982 /*
5983 * migrate cur->content to attrs
5984 */
5985 tmp = cur->content;
5986 cur->content = tmp->next;
5987 tmp->next = cur->attrs;
5988 cur->attrs = tmp;
5989 } else {
5990 /*
5991 * cur->content can generate elements or text
5992 */
5993 break;
5994 }
5995 }
5996 pre = cur->content;
5997 while ((pre != NULL) && (pre->next != NULL)) {
5998 tmp = pre->next;
5999 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
6000 if (attronly == 1) {
6001 /*
6002 * migrate tmp to attrs
6003 */
6004 pre->next = tmp->next;
6005 tmp->next = cur->attrs;
6006 cur->attrs = tmp;
6007 } else {
6008 pre = tmp;
6009 }
6010 }
6011 }
6012 /*
6013 * This may result in a simplification
6014 */
6015 if ((cur->type == XML_RELAXNG_GROUP) ||
6016 (cur->type == XML_RELAXNG_INTERLEAVE)) {
6017 if (cur->content == NULL)
6018 cur->type = XML_RELAXNG_EMPTY;
6019 else if (cur->content->next == NULL) {
6020 if ((parent == NULL) && (prev == NULL)) {
6021 cur->type = XML_RELAXNG_NOOP;
6022 } else if (prev == NULL) {
6023 parent->content = cur->content;
6024 cur->content->next = cur->next;
6025 cur = cur->content;
6026 } else {
6027 cur->content->next = cur->next;
6028 prev->next = cur->content;
6029 cur = cur->content;
6030 }
6031 }
6032 }
6033 /*
6034 * the current node may have been transformed back
6035 */
6036 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6037 (cur->content != NULL) &&
6038 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6039 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6040 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6041 if ((parent != NULL) &&
6042 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6043 (parent->type == XML_RELAXNG_LIST) ||
6044 (parent->type == XML_RELAXNG_GROUP) ||
6045 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6046 (parent->type == XML_RELAXNG_ONEORMORE) ||
6047 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6048 parent->type = XML_RELAXNG_NOT_ALLOWED;
6049 break;
6050 }
6051 if ((parent != NULL) &&
6052 (parent->type == XML_RELAXNG_CHOICE)) {
6053 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6054 } else
6055 prev = cur;
6056 } else if (cur->type == XML_RELAXNG_EMPTY) {
6057 if ((parent != NULL) &&
6058 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6059 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6060 parent->type = XML_RELAXNG_EMPTY;
6061 break;
6062 }
6063 if ((parent != NULL) &&
6064 ((parent->type == XML_RELAXNG_GROUP) ||
6065 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6066 (parent->type == XML_RELAXNG_CHOICE))) {
6067 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6068 } else
6069 prev = cur;
6070 } else {
6071 prev = cur;
6072 }
6073 }
6074 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006075 }
6076}
6077
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006078/**
6079 * xmlRelaxNGGroupContentType:
6080 * @ct1: the first content type
6081 * @ct2: the second content type
6082 *
6083 * Try to group 2 content types
6084 *
6085 * Returns the content type
6086 */
6087static xmlRelaxNGContentType
6088xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006089 xmlRelaxNGContentType ct2)
6090{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006091 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006092 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6093 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006094 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006095 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006096 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006097 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006098 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006099 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6100 return (XML_RELAXNG_CONTENT_COMPLEX);
6101 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006102}
6103
6104/**
6105 * xmlRelaxNGMaxContentType:
6106 * @ct1: the first content type
6107 * @ct2: the second content type
6108 *
6109 * Compute the max content-type
6110 *
6111 * Returns the content type
6112 */
6113static xmlRelaxNGContentType
6114xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006115 xmlRelaxNGContentType ct2)
6116{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006117 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006118 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6119 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006120 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006121 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6122 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006123 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006124 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6125 return (XML_RELAXNG_CONTENT_COMPLEX);
6126 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006127}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006128
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006129/**
6130 * xmlRelaxNGCheckRules:
6131 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006132 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006133 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006134 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006135 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006136 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006137 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006138 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006139 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006140static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006141xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6142 xmlRelaxNGDefinePtr cur, int flags,
6143 xmlRelaxNGType ptype)
6144{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006145 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006146 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006147
Daniel Veillardfd573f12003-03-16 17:52:32 +00006148 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006149 ret = XML_RELAXNG_CONTENT_EMPTY;
6150 if ((cur->type == XML_RELAXNG_REF) ||
6151 (cur->type == XML_RELAXNG_PARENTREF)) {
6152 if (flags & XML_RELAXNG_IN_LIST) {
6153 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6154 "Found forbidden pattern list//ref\n", NULL,
6155 NULL);
6156 }
6157 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6158 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6159 "Found forbidden pattern data/except//ref\n",
6160 NULL, NULL);
6161 }
6162 if (cur->depth > -4) {
6163 cur->depth = -4;
6164 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6165 flags, cur->type);
6166 cur->depth = ret - 15;
6167 } else if (cur->depth == -4) {
6168 ret = XML_RELAXNG_CONTENT_COMPLEX;
6169 } else {
6170 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6171 }
6172 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6173 /*
6174 * The 7.3 Attribute derivation rule for groups is plugged there
6175 */
6176 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6177 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6178 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6179 "Found forbidden pattern data/except//element(ref)\n",
6180 NULL, NULL);
6181 }
6182 if (flags & XML_RELAXNG_IN_LIST) {
6183 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6184 "Found forbidden pattern list//element(ref)\n",
6185 NULL, NULL);
6186 }
6187 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6188 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6189 "Found forbidden pattern attribute//element(ref)\n",
6190 NULL, NULL);
6191 }
6192 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6193 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6194 "Found forbidden pattern attribute//element(ref)\n",
6195 NULL, NULL);
6196 }
6197 /*
6198 * reset since in the simple form elements are only child
6199 * of grammar/define
6200 */
6201 nflags = 0;
6202 ret =
6203 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6204 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6205 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6206 "Element %s attributes have a content type error\n",
6207 cur->name, NULL);
6208 }
6209 ret =
6210 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6211 cur->type);
6212 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6213 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6214 "Element %s has a content type error\n",
6215 cur->name, NULL);
6216 } else {
6217 ret = XML_RELAXNG_CONTENT_COMPLEX;
6218 }
6219 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6220 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6221 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6222 "Found forbidden pattern attribute//attribute\n",
6223 NULL, NULL);
6224 }
6225 if (flags & XML_RELAXNG_IN_LIST) {
6226 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6227 "Found forbidden pattern list//attribute\n",
6228 NULL, NULL);
6229 }
6230 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6231 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6232 "Found forbidden pattern oneOrMore//group//attribute\n",
6233 NULL, NULL);
6234 }
6235 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6236 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6237 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6238 NULL, NULL);
6239 }
6240 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6241 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6242 "Found forbidden pattern data/except//attribute\n",
6243 NULL, NULL);
6244 }
6245 if (flags & XML_RELAXNG_IN_START) {
6246 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6247 "Found forbidden pattern start//attribute\n",
6248 NULL, NULL);
6249 }
6250 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6251 && (cur->name == NULL)) {
6252 if (cur->ns == NULL) {
6253 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6254 "Found anyName attribute without oneOrMore ancestor\n",
6255 NULL, NULL);
6256 } else {
6257 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6258 "Found nsName attribute without oneOrMore ancestor\n",
6259 NULL, NULL);
6260 }
6261 }
6262 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6263 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6264 ret = XML_RELAXNG_CONTENT_EMPTY;
6265 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6266 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6267 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6268 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6269 "Found forbidden pattern data/except//oneOrMore\n",
6270 NULL, NULL);
6271 }
6272 if (flags & XML_RELAXNG_IN_START) {
6273 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6274 "Found forbidden pattern start//oneOrMore\n",
6275 NULL, NULL);
6276 }
6277 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6278 ret =
6279 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6280 cur->type);
6281 ret = xmlRelaxNGGroupContentType(ret, ret);
6282 } else if (cur->type == XML_RELAXNG_LIST) {
6283 if (flags & XML_RELAXNG_IN_LIST) {
6284 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6285 "Found forbidden pattern list//list\n", NULL,
6286 NULL);
6287 }
6288 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6289 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6290 "Found forbidden pattern data/except//list\n",
6291 NULL, NULL);
6292 }
6293 if (flags & XML_RELAXNG_IN_START) {
6294 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6295 "Found forbidden pattern start//list\n", NULL,
6296 NULL);
6297 }
6298 nflags = flags | XML_RELAXNG_IN_LIST;
6299 ret =
6300 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6301 cur->type);
6302 } else if (cur->type == XML_RELAXNG_GROUP) {
6303 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6304 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6305 "Found forbidden pattern data/except//group\n",
6306 NULL, NULL);
6307 }
6308 if (flags & XML_RELAXNG_IN_START) {
6309 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6310 "Found forbidden pattern start//group\n", NULL,
6311 NULL);
6312 }
6313 if (flags & XML_RELAXNG_IN_ONEORMORE)
6314 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6315 else
6316 nflags = flags;
6317 ret =
6318 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6319 cur->type);
6320 /*
6321 * The 7.3 Attribute derivation rule for groups is plugged there
6322 */
6323 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6324 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6325 if (flags & XML_RELAXNG_IN_LIST) {
6326 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6327 "Found forbidden pattern list//interleave\n",
6328 NULL, NULL);
6329 }
6330 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6331 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6332 "Found forbidden pattern data/except//interleave\n",
6333 NULL, NULL);
6334 }
6335 if (flags & XML_RELAXNG_IN_START) {
6336 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6337 "Found forbidden pattern start//interleave\n",
6338 NULL, NULL);
6339 }
6340 if (flags & XML_RELAXNG_IN_ONEORMORE)
6341 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6342 else
6343 nflags = flags;
6344 ret =
6345 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6346 cur->type);
6347 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6348 if ((cur->parent != NULL) &&
6349 (cur->parent->type == XML_RELAXNG_DATATYPE))
6350 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6351 else
6352 nflags = flags;
6353 ret =
6354 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6355 cur->type);
6356 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6357 if (flags & XML_RELAXNG_IN_START) {
6358 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6359 "Found forbidden pattern start//data\n", NULL,
6360 NULL);
6361 }
6362 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6363 ret = XML_RELAXNG_CONTENT_SIMPLE;
6364 } else if (cur->type == XML_RELAXNG_VALUE) {
6365 if (flags & XML_RELAXNG_IN_START) {
6366 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6367 "Found forbidden pattern start//value\n", NULL,
6368 NULL);
6369 }
6370 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6371 ret = XML_RELAXNG_CONTENT_SIMPLE;
6372 } else if (cur->type == XML_RELAXNG_TEXT) {
6373 if (flags & XML_RELAXNG_IN_LIST) {
6374 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6375 "Found forbidden pattern list//text\n", NULL,
6376 NULL);
6377 }
6378 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6379 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6380 "Found forbidden pattern data/except//text\n",
6381 NULL, NULL);
6382 }
6383 if (flags & XML_RELAXNG_IN_START) {
6384 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6385 "Found forbidden pattern start//text\n", NULL,
6386 NULL);
6387 }
6388 ret = XML_RELAXNG_CONTENT_COMPLEX;
6389 } else if (cur->type == XML_RELAXNG_EMPTY) {
6390 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6391 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6392 "Found forbidden pattern data/except//empty\n",
6393 NULL, NULL);
6394 }
6395 if (flags & XML_RELAXNG_IN_START) {
6396 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6397 "Found forbidden pattern start//empty\n", NULL,
6398 NULL);
6399 }
6400 ret = XML_RELAXNG_CONTENT_EMPTY;
6401 } else if (cur->type == XML_RELAXNG_CHOICE) {
6402 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6403 ret =
6404 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6405 } else {
6406 ret =
6407 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6408 }
6409 cur = cur->next;
6410 if (ptype == XML_RELAXNG_GROUP) {
6411 val = xmlRelaxNGGroupContentType(val, ret);
6412 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6413 tmp = xmlRelaxNGGroupContentType(val, ret);
6414 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6415 tmp = xmlRelaxNGMaxContentType(val, ret);
6416 } else if (ptype == XML_RELAXNG_CHOICE) {
6417 val = xmlRelaxNGMaxContentType(val, ret);
6418 } else if (ptype == XML_RELAXNG_LIST) {
6419 val = XML_RELAXNG_CONTENT_SIMPLE;
6420 } else if (ptype == XML_RELAXNG_EXCEPT) {
6421 if (ret == XML_RELAXNG_CONTENT_ERROR)
6422 val = XML_RELAXNG_CONTENT_ERROR;
6423 else
6424 val = XML_RELAXNG_CONTENT_SIMPLE;
6425 } else {
6426 val = xmlRelaxNGGroupContentType(val, ret);
6427 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006428
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006429 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006430 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006431}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006432
6433/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006434 * xmlRelaxNGParseGrammar:
6435 * @ctxt: a Relax-NG parser context
6436 * @nodes: grammar children nodes
6437 *
6438 * parse a Relax-NG <grammar> node
6439 *
6440 * Returns the internal xmlRelaxNGGrammarPtr built or
6441 * NULL in case of error
6442 */
6443static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006444xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6445{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006446 xmlRelaxNGGrammarPtr ret, tmp, old;
6447
Daniel Veillardc482e262003-02-26 14:48:48 +00006448#ifdef DEBUG_GRAMMAR
6449 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6450#endif
6451
Daniel Veillard6eadf632003-01-23 18:29:16 +00006452 ret = xmlRelaxNGNewGrammar(ctxt);
6453 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006454 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006455
6456 /*
6457 * Link the new grammar in the tree
6458 */
6459 ret->parent = ctxt->grammar;
6460 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006461 tmp = ctxt->grammar->children;
6462 if (tmp == NULL) {
6463 ctxt->grammar->children = ret;
6464 } else {
6465 while (tmp->next != NULL)
6466 tmp = tmp->next;
6467 tmp->next = ret;
6468 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469 }
6470
6471 old = ctxt->grammar;
6472 ctxt->grammar = ret;
6473 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6474 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006475 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006476 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6477 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006478 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006479 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6480 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006481 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006482
6483 /*
6484 * Apply 4.17 mergingd rules to defines and starts
6485 */
6486 xmlRelaxNGCombineStart(ctxt, ret);
6487 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006488 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6489 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006490 }
6491
6492 /*
6493 * link together defines and refs in this grammar
6494 */
6495 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006496 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6497 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006498 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006499
Daniel Veillard6eadf632003-01-23 18:29:16 +00006500 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006501 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006502}
6503
6504/**
6505 * xmlRelaxNGParseDocument:
6506 * @ctxt: a Relax-NG parser context
6507 * @node: the root node of the RelaxNG schema
6508 *
6509 * parse a Relax-NG definition resource and build an internal
6510 * xmlRelaxNG struture which can be used to validate instances.
6511 *
6512 * Returns the internal XML RelaxNG structure built or
6513 * NULL in case of error
6514 */
6515static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006516xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6517{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006518 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006519 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006520 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006521
6522 if ((ctxt == NULL) || (node == NULL))
6523 return (NULL);
6524
6525 schema = xmlRelaxNGNewRelaxNG(ctxt);
6526 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006527 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006528
Daniel Veillard276be4a2003-01-24 01:03:34 +00006529 olddefine = ctxt->define;
6530 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006531 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006532 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006533 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006534 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006535
Daniel Veillard4c004142003-10-07 11:33:24 +00006536 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6537 if (schema->topgrammar == NULL) {
6538 return (schema);
6539 }
6540 /*
6541 * Link the new grammar in the tree
6542 */
6543 ret->parent = ctxt->grammar;
6544 if (ctxt->grammar != NULL) {
6545 tmp = ctxt->grammar->children;
6546 if (tmp == NULL) {
6547 ctxt->grammar->children = ret;
6548 } else {
6549 while (tmp->next != NULL)
6550 tmp = tmp->next;
6551 tmp->next = ret;
6552 }
6553 }
6554 old = ctxt->grammar;
6555 ctxt->grammar = ret;
6556 xmlRelaxNGParseStart(ctxt, node);
6557 if (old != NULL)
6558 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006559 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006560 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006561 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006562 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6563 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6564 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6565 while ((schema->topgrammar->start != NULL) &&
6566 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6567 (schema->topgrammar->start->next != NULL))
6568 schema->topgrammar->start =
6569 schema->topgrammar->start->content;
6570 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6571 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6572 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006573 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006574#ifdef DEBUG
6575 if (schema == NULL)
6576 xmlGenericError(xmlGenericErrorContext,
6577 "xmlRelaxNGParseDocument() failed\n");
6578#endif
6579
6580 return (schema);
6581}
6582
6583/************************************************************************
6584 * *
6585 * Reading RelaxNGs *
6586 * *
6587 ************************************************************************/
6588
6589/**
6590 * xmlRelaxNGNewParserCtxt:
6591 * @URL: the location of the schema
6592 *
6593 * Create an XML RelaxNGs parse context for that file/resource expected
6594 * to contain an XML RelaxNGs file.
6595 *
6596 * Returns the parser context or NULL in case of error
6597 */
6598xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006599xmlRelaxNGNewParserCtxt(const char *URL)
6600{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006601 xmlRelaxNGParserCtxtPtr ret;
6602
6603 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006604 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006605
Daniel Veillard4c004142003-10-07 11:33:24 +00006606 ret =
6607 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006608 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006609 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006610 return (NULL);
6611 }
6612 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006613 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006614 ret->error = xmlGenericError;
6615 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006616 return (ret);
6617}
6618
6619/**
6620 * xmlRelaxNGNewMemParserCtxt:
6621 * @buffer: a pointer to a char array containing the schemas
6622 * @size: the size of the array
6623 *
6624 * Create an XML RelaxNGs parse context for that memory buffer expected
6625 * to contain an XML RelaxNGs file.
6626 *
6627 * Returns the parser context or NULL in case of error
6628 */
6629xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006630xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6631{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006632 xmlRelaxNGParserCtxtPtr ret;
6633
6634 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006635 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006636
Daniel Veillard4c004142003-10-07 11:33:24 +00006637 ret =
6638 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006639 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006640 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006641 return (NULL);
6642 }
6643 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6644 ret->buffer = buffer;
6645 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006646 ret->error = xmlGenericError;
6647 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006648 return (ret);
6649}
6650
6651/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006652 * xmlRelaxNGNewDocParserCtxt:
6653 * @doc: a preparsed document tree
6654 *
6655 * Create an XML RelaxNGs parser context for that document.
6656 * Note: since the process of compiling a RelaxNG schemas modifies the
6657 * document, the @doc parameter is duplicated internally.
6658 *
6659 * Returns the parser context or NULL in case of error
6660 */
6661xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006662xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6663{
Daniel Veillard33300b42003-04-17 09:09:19 +00006664 xmlRelaxNGParserCtxtPtr ret;
6665 xmlDocPtr copy;
6666
6667 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006668 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006669 copy = xmlCopyDoc(doc, 1);
6670 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006671 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006672
Daniel Veillard4c004142003-10-07 11:33:24 +00006673 ret =
6674 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006675 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006676 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006677 return (NULL);
6678 }
6679 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6680 ret->document = copy;
6681 ret->userData = xmlGenericErrorContext;
6682 return (ret);
6683}
6684
6685/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006686 * xmlRelaxNGFreeParserCtxt:
6687 * @ctxt: the schema parser context
6688 *
6689 * Free the resources associated to the schema parser context
6690 */
6691void
Daniel Veillard4c004142003-10-07 11:33:24 +00006692xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6693{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006694 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006695 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006696 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006697 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006698 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006699 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006700 if (ctxt->interleaves != NULL)
6701 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006702 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006703 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006704 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006705 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006706 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006707 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006708 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006709 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006710 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006711 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006712
Daniel Veillard4c004142003-10-07 11:33:24 +00006713 for (i = 0; i < ctxt->defNr; i++)
6714 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6715 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006716 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006717 xmlFree(ctxt);
6718}
6719
Daniel Veillard6eadf632003-01-23 18:29:16 +00006720/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006721 * xmlRelaxNGNormExtSpace:
6722 * @value: a value
6723 *
6724 * Removes the leading and ending spaces of the value
6725 * The string is modified "in situ"
6726 */
6727static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006728xmlRelaxNGNormExtSpace(xmlChar * value)
6729{
Daniel Veillardd2298792003-02-14 16:54:11 +00006730 xmlChar *start = value;
6731 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006732
Daniel Veillard4c004142003-10-07 11:33:24 +00006733 if (value == NULL)
6734 return;
6735
6736 while (IS_BLANK(*cur))
6737 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006738 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006739 do {
6740 while ((*cur != 0) && (!IS_BLANK(*cur)))
6741 cur++;
6742 if (*cur == 0)
6743 return;
6744 start = cur;
6745 while (IS_BLANK(*cur))
6746 cur++;
6747 if (*cur == 0) {
6748 *start = 0;
6749 return;
6750 }
6751 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006752 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006753 do {
6754 while ((*cur != 0) && (!IS_BLANK(*cur)))
6755 *start++ = *cur++;
6756 if (*cur == 0) {
6757 *start = 0;
6758 return;
6759 }
6760 /* don't try to normalize the inner spaces */
6761 while (IS_BLANK(*cur))
6762 cur++;
6763 *start++ = *cur++;
6764 if (*cur == 0) {
6765 *start = 0;
6766 return;
6767 }
6768 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006769 }
6770}
6771
6772/**
6773 * xmlRelaxNGCheckAttributes:
6774 * @ctxt: a Relax-NG parser context
6775 * @node: a Relax-NG node
6776 *
6777 * Check all the attributes on the given node
6778 */
6779static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006780xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6781{
Daniel Veillardd2298792003-02-14 16:54:11 +00006782 xmlAttrPtr cur, next;
6783
6784 cur = node->properties;
6785 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006786 next = cur->next;
6787 if ((cur->ns == NULL) ||
6788 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6789 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6790 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6791 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6792 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6793 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6794 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6795 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6796 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6797 "Attribute %s is not allowed on %s\n",
6798 cur->name, node->name);
6799 }
6800 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6801 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6802 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6803 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6804 "Attribute %s is not allowed on %s\n",
6805 cur->name, node->name);
6806 }
6807 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6808 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6809 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6810 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6811 "Attribute %s is not allowed on %s\n",
6812 cur->name, node->name);
6813 }
6814 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6815 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6816 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6817 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6818 "Attribute %s is not allowed on %s\n",
6819 cur->name, node->name);
6820 }
6821 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6822 xmlChar *val;
6823 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006824
Daniel Veillard4c004142003-10-07 11:33:24 +00006825 val = xmlNodeListGetString(node->doc, cur->children, 1);
6826 if (val != NULL) {
6827 if (val[0] != 0) {
6828 uri = xmlParseURI((const char *) val);
6829 if (uri == NULL) {
6830 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6831 "Attribute %s contains invalid URI %s\n",
6832 cur->name, val);
6833 } else {
6834 if (uri->scheme == NULL) {
6835 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6836 "Attribute %s URI %s is not absolute\n",
6837 cur->name, val);
6838 }
6839 if (uri->fragment != NULL) {
6840 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6841 "Attribute %s URI %s has a fragment ID\n",
6842 cur->name, val);
6843 }
6844 xmlFreeURI(uri);
6845 }
6846 }
6847 xmlFree(val);
6848 }
6849 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6850 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6851 "Unknown attribute %s on %s\n", cur->name,
6852 node->name);
6853 }
6854 }
6855 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006856 }
6857}
6858
6859/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006860 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006861 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006862 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006863 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006864 * Cleanup the subtree from unwanted nodes for parsing, resolve
6865 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006866 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006867static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006868xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6869{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006870 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006871
Daniel Veillard6eadf632003-01-23 18:29:16 +00006872 delete = NULL;
6873 cur = root;
6874 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006875 if (delete != NULL) {
6876 xmlUnlinkNode(delete);
6877 xmlFreeNode(delete);
6878 delete = NULL;
6879 }
6880 if (cur->type == XML_ELEMENT_NODE) {
6881 /*
6882 * Simplification 4.1. Annotations
6883 */
6884 if ((cur->ns == NULL) ||
6885 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6886 if ((cur->parent != NULL) &&
6887 (cur->parent->type == XML_ELEMENT_NODE) &&
6888 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6889 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6890 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6891 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6892 "element %s doesn't allow foreign elements\n",
6893 cur->parent->name, NULL);
6894 }
6895 delete = cur;
6896 goto skip_children;
6897 } else {
6898 xmlRelaxNGCleanupAttributes(ctxt, cur);
6899 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6900 xmlChar *href, *ns, *base, *URL;
6901 xmlRelaxNGDocumentPtr docu;
6902 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006903
Daniel Veillard4c004142003-10-07 11:33:24 +00006904 ns = xmlGetProp(cur, BAD_CAST "ns");
6905 if (ns == NULL) {
6906 tmp = cur->parent;
6907 while ((tmp != NULL) &&
6908 (tmp->type == XML_ELEMENT_NODE)) {
6909 ns = xmlGetProp(tmp, BAD_CAST "ns");
6910 if (ns != NULL)
6911 break;
6912 tmp = tmp->parent;
6913 }
6914 }
6915 href = xmlGetProp(cur, BAD_CAST "href");
6916 if (href == NULL) {
6917 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6918 "xmlRelaxNGParse: externalRef has no href attribute\n",
6919 NULL, NULL);
6920 delete = cur;
6921 goto skip_children;
6922 }
6923 base = xmlNodeGetBase(cur->doc, cur);
6924 URL = xmlBuildURI(href, base);
6925 if (URL == NULL) {
6926 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6927 "Failed to compute URL for externalRef %s\n",
6928 href, NULL);
6929 if (href != NULL)
6930 xmlFree(href);
6931 if (base != NULL)
6932 xmlFree(base);
6933 delete = cur;
6934 goto skip_children;
6935 }
6936 if (href != NULL)
6937 xmlFree(href);
6938 if (base != NULL)
6939 xmlFree(base);
6940 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6941 if (docu == NULL) {
6942 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6943 "Failed to load externalRef %s\n", URL,
6944 NULL);
6945 xmlFree(URL);
6946 delete = cur;
6947 goto skip_children;
6948 }
6949 if (ns != NULL)
6950 xmlFree(ns);
6951 xmlFree(URL);
6952 cur->_private = docu;
6953 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6954 xmlChar *href, *ns, *base, *URL;
6955 xmlRelaxNGIncludePtr incl;
6956 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006957
Daniel Veillard4c004142003-10-07 11:33:24 +00006958 href = xmlGetProp(cur, BAD_CAST "href");
6959 if (href == NULL) {
6960 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6961 "xmlRelaxNGParse: include has no href attribute\n",
6962 NULL, NULL);
6963 delete = cur;
6964 goto skip_children;
6965 }
6966 base = xmlNodeGetBase(cur->doc, cur);
6967 URL = xmlBuildURI(href, base);
6968 if (URL == NULL) {
6969 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6970 "Failed to compute URL for include %s\n",
6971 href, NULL);
6972 if (href != NULL)
6973 xmlFree(href);
6974 if (base != NULL)
6975 xmlFree(base);
6976 delete = cur;
6977 goto skip_children;
6978 }
6979 if (href != NULL)
6980 xmlFree(href);
6981 if (base != NULL)
6982 xmlFree(base);
6983 ns = xmlGetProp(cur, BAD_CAST "ns");
6984 if (ns == NULL) {
6985 tmp = cur->parent;
6986 while ((tmp != NULL) &&
6987 (tmp->type == XML_ELEMENT_NODE)) {
6988 ns = xmlGetProp(tmp, BAD_CAST "ns");
6989 if (ns != NULL)
6990 break;
6991 tmp = tmp->parent;
6992 }
6993 }
6994 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6995 if (ns != NULL)
6996 xmlFree(ns);
6997 if (incl == NULL) {
6998 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
6999 "Failed to load include %s\n", URL,
7000 NULL);
7001 xmlFree(URL);
7002 delete = cur;
7003 goto skip_children;
7004 }
7005 xmlFree(URL);
7006 cur->_private = incl;
7007 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7008 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7009 {
7010 xmlChar *name, *ns;
7011 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007012
Daniel Veillard4c004142003-10-07 11:33:24 +00007013 /*
7014 * Simplification 4.8. name attribute of element
7015 * and attribute elements
7016 */
7017 name = xmlGetProp(cur, BAD_CAST "name");
7018 if (name != NULL) {
7019 if (cur->children == NULL) {
7020 text =
7021 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7022 name);
7023 } else {
7024 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007025
Daniel Veillard4c004142003-10-07 11:33:24 +00007026 node = xmlNewNode(cur->ns, BAD_CAST "name");
7027 if (node != NULL) {
7028 xmlAddPrevSibling(cur->children, node);
7029 text = xmlNewText(name);
7030 xmlAddChild(node, text);
7031 text = node;
7032 }
7033 }
7034 if (text == NULL) {
7035 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7036 "Failed to create a name %s element\n",
7037 name, NULL);
7038 }
7039 xmlUnsetProp(cur, BAD_CAST "name");
7040 xmlFree(name);
7041 ns = xmlGetProp(cur, BAD_CAST "ns");
7042 if (ns != NULL) {
7043 if (text != NULL) {
7044 xmlSetProp(text, BAD_CAST "ns", ns);
7045 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7046 }
7047 xmlFree(ns);
7048 } else if (xmlStrEqual(cur->name,
7049 BAD_CAST "attribute")) {
7050 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7051 }
7052 }
7053 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7054 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7055 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7056 /*
7057 * Simplification 4.8. name attribute of element
7058 * and attribute elements
7059 */
7060 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7061 xmlNodePtr node;
7062 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007063
Daniel Veillard4c004142003-10-07 11:33:24 +00007064 node = cur->parent;
7065 while ((node != NULL) &&
7066 (node->type == XML_ELEMENT_NODE)) {
7067 ns = xmlGetProp(node, BAD_CAST "ns");
7068 if (ns != NULL) {
7069 break;
7070 }
7071 node = node->parent;
7072 }
7073 if (ns == NULL) {
7074 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7075 } else {
7076 xmlSetProp(cur, BAD_CAST "ns", ns);
7077 xmlFree(ns);
7078 }
7079 }
7080 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7081 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007082
Daniel Veillard4c004142003-10-07 11:33:24 +00007083 /*
7084 * Simplification: 4.10. QNames
7085 */
7086 name = xmlNodeGetContent(cur);
7087 if (name != NULL) {
7088 local = xmlSplitQName2(name, &prefix);
7089 if (local != NULL) {
7090 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007091
Daniel Veillard4c004142003-10-07 11:33:24 +00007092 ns = xmlSearchNs(cur->doc, cur, prefix);
7093 if (ns == NULL) {
7094 xmlRngPErr(ctxt, cur,
7095 XML_RNGP_PREFIX_UNDEFINED,
7096 "xmlRelaxNGParse: no namespace for prefix %s\n",
7097 prefix, NULL);
7098 } else {
7099 xmlSetProp(cur, BAD_CAST "ns",
7100 ns->href);
7101 xmlNodeSetContent(cur, local);
7102 }
7103 xmlFree(local);
7104 xmlFree(prefix);
7105 }
7106 xmlFree(name);
7107 }
7108 }
7109 /*
7110 * 4.16
7111 */
7112 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7113 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7114 xmlRngPErr(ctxt, cur,
7115 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7116 "Found nsName/except//nsName forbidden construct\n",
7117 NULL, NULL);
7118 }
7119 }
7120 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7121 (cur != root)) {
7122 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007123
Daniel Veillard4c004142003-10-07 11:33:24 +00007124 /*
7125 * 4.16
7126 */
7127 if ((cur->parent != NULL) &&
7128 (xmlStrEqual
7129 (cur->parent->name, BAD_CAST "anyName"))) {
7130 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7131 xmlRelaxNGCleanupTree(ctxt, cur);
7132 ctxt->flags = oldflags;
7133 goto skip_children;
7134 } else if ((cur->parent != NULL) &&
7135 (xmlStrEqual
7136 (cur->parent->name, BAD_CAST "nsName"))) {
7137 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7138 xmlRelaxNGCleanupTree(ctxt, cur);
7139 ctxt->flags = oldflags;
7140 goto skip_children;
7141 }
7142 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7143 /*
7144 * 4.16
7145 */
7146 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7147 xmlRngPErr(ctxt, cur,
7148 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7149 "Found anyName/except//anyName forbidden construct\n",
7150 NULL, NULL);
7151 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7152 xmlRngPErr(ctxt, cur,
7153 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7154 "Found nsName/except//anyName forbidden construct\n",
7155 NULL, NULL);
7156 }
7157 }
7158 /*
7159 * Thisd is not an else since "include" is transformed
7160 * into a div
7161 */
7162 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7163 xmlChar *ns;
7164 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007165
Daniel Veillard4c004142003-10-07 11:33:24 +00007166 /*
7167 * implements rule 4.11
7168 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007169
Daniel Veillard4c004142003-10-07 11:33:24 +00007170 ns = xmlGetProp(cur, BAD_CAST "ns");
7171
7172 child = cur->children;
7173 ins = cur;
7174 while (child != NULL) {
7175 if (ns != NULL) {
7176 if (!xmlHasProp(child, BAD_CAST "ns")) {
7177 xmlSetProp(child, BAD_CAST "ns", ns);
7178 }
7179 }
7180 tmp = child->next;
7181 xmlUnlinkNode(child);
7182 ins = xmlAddNextSibling(ins, child);
7183 child = tmp;
7184 }
7185 if (ns != NULL)
7186 xmlFree(ns);
7187 delete = cur;
7188 goto skip_children;
7189 }
7190 }
7191 }
7192 /*
7193 * Simplification 4.2 whitespaces
7194 */
7195 else if ((cur->type == XML_TEXT_NODE) ||
7196 (cur->type == XML_CDATA_SECTION_NODE)) {
7197 if (IS_BLANK_NODE(cur)) {
7198 if (cur->parent->type == XML_ELEMENT_NODE) {
7199 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7200 &&
7201 (!xmlStrEqual
7202 (cur->parent->name, BAD_CAST "param")))
7203 delete = cur;
7204 } else {
7205 delete = cur;
7206 goto skip_children;
7207 }
7208 }
7209 } else {
7210 delete = cur;
7211 goto skip_children;
7212 }
7213
7214 /*
7215 * Skip to next node
7216 */
7217 if (cur->children != NULL) {
7218 if ((cur->children->type != XML_ENTITY_DECL) &&
7219 (cur->children->type != XML_ENTITY_REF_NODE) &&
7220 (cur->children->type != XML_ENTITY_NODE)) {
7221 cur = cur->children;
7222 continue;
7223 }
7224 }
7225 skip_children:
7226 if (cur->next != NULL) {
7227 cur = cur->next;
7228 continue;
7229 }
7230
7231 do {
7232 cur = cur->parent;
7233 if (cur == NULL)
7234 break;
7235 if (cur == root) {
7236 cur = NULL;
7237 break;
7238 }
7239 if (cur->next != NULL) {
7240 cur = cur->next;
7241 break;
7242 }
7243 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007244 }
7245 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007246 xmlUnlinkNode(delete);
7247 xmlFreeNode(delete);
7248 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007249 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007250}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007251
Daniel Veillardc5312d72003-02-21 17:14:10 +00007252/**
7253 * xmlRelaxNGCleanupDoc:
7254 * @ctxt: a Relax-NG parser context
7255 * @doc: an xmldocPtr document pointer
7256 *
7257 * Cleanup the document from unwanted nodes for parsing, resolve
7258 * Include and externalRef lookups.
7259 *
7260 * Returns the cleaned up document or NULL in case of error
7261 */
7262static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007263xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7264{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007265 xmlNodePtr root;
7266
7267 /*
7268 * Extract the root
7269 */
7270 root = xmlDocGetRootElement(doc);
7271 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007272 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7273 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007274 return (NULL);
7275 }
7276 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007277 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007278}
7279
7280/**
7281 * xmlRelaxNGParse:
7282 * @ctxt: a Relax-NG parser context
7283 *
7284 * parse a schema definition resource and build an internal
7285 * XML Shema struture which can be used to validate instances.
7286 * *WARNING* this interface is highly subject to change
7287 *
7288 * Returns the internal XML RelaxNG structure built from the resource or
7289 * NULL in case of error
7290 */
7291xmlRelaxNGPtr
7292xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7293{
7294 xmlRelaxNGPtr ret = NULL;
7295 xmlDocPtr doc;
7296 xmlNodePtr root;
7297
7298 xmlRelaxNGInitTypes();
7299
7300 if (ctxt == NULL)
7301 return (NULL);
7302
7303 /*
7304 * First step is to parse the input document into an DOM/Infoset
7305 */
7306 if (ctxt->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007307 doc = xmlParseFile((const char *) ctxt->URL);
7308 if (doc == NULL) {
7309 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7310 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7311 NULL);
7312 return (NULL);
7313 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007314 } else if (ctxt->buffer != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007315 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7316 if (doc == NULL) {
7317 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7318 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7319 NULL);
7320 return (NULL);
7321 }
7322 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7323 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007324 } else if (ctxt->document != NULL) {
7325 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007326 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007327 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7328 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7329 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007330 }
7331 ctxt->document = doc;
7332
7333 /*
7334 * Some preprocessing of the document content
7335 */
7336 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7337 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007338 xmlFreeDoc(ctxt->document);
7339 ctxt->document = NULL;
7340 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007341 }
7342
Daniel Veillard6eadf632003-01-23 18:29:16 +00007343 /*
7344 * Then do the parsing for good
7345 */
7346 root = xmlDocGetRootElement(doc);
7347 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007348 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7349 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7350 ctxt->URL, NULL);
7351 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007352 return (NULL);
7353 }
7354 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007355 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007356 xmlFreeDoc(doc);
7357 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007358 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007359
7360 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007361 * Check the ref/defines links
7362 */
7363 /*
7364 * try to preprocess interleaves
7365 */
7366 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007367 xmlHashScan(ctxt->interleaves,
7368 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007369 }
7370
7371 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007372 * if there was a parsing error return NULL
7373 */
7374 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007375 xmlRelaxNGFree(ret);
7376 ctxt->document = NULL;
7377 xmlFreeDoc(doc);
7378 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007379 }
7380
7381 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007382 * try to compile (parts of) the schemas
7383 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007384 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7385 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007386 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007387
Daniel Veillard4c004142003-10-07 11:33:24 +00007388 def = xmlRelaxNGNewDefine(ctxt, NULL);
7389 if (def != NULL) {
7390 def->type = XML_RELAXNG_START;
7391 def->content = ret->topgrammar->start;
7392 ret->topgrammar->start = def;
7393 }
7394 }
7395 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007396 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007397
7398 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007399 * Transfer the pointer for cleanup at the schema level.
7400 */
7401 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007402 ctxt->document = NULL;
7403 ret->documents = ctxt->documents;
7404 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007405
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007406 ret->includes = ctxt->includes;
7407 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007408 ret->defNr = ctxt->defNr;
7409 ret->defTab = ctxt->defTab;
7410 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007411 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007412 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007413
7414 return (ret);
7415}
Daniel Veillard4c004142003-10-07 11:33:24 +00007416
Daniel Veillard6eadf632003-01-23 18:29:16 +00007417/**
7418 * xmlRelaxNGSetParserErrors:
7419 * @ctxt: a Relax-NG validation context
7420 * @err: the error callback
7421 * @warn: the warning callback
7422 * @ctx: contextual data for the callbacks
7423 *
7424 * Set the callback functions used to handle errors for a validation context
7425 */
7426void
7427xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007428 xmlRelaxNGValidityErrorFunc err,
7429 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7430{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007431 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007432 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007433 ctxt->error = err;
7434 ctxt->warning = warn;
7435 ctxt->userData = ctx;
7436}
Daniel Veillard409a8142003-07-18 15:16:57 +00007437
7438/**
7439 * xmlRelaxNGGetParserErrors:
7440 * @ctxt: a Relax-NG validation context
7441 * @err: the error callback result
7442 * @warn: the warning callback result
7443 * @ctx: contextual data for the callbacks result
7444 *
7445 * Get the callback information used to handle errors for a validation context
7446 *
7447 * Returns -1 in case of failure, 0 otherwise.
7448 */
7449int
7450xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007451 xmlRelaxNGValidityErrorFunc * err,
7452 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7453{
Daniel Veillard409a8142003-07-18 15:16:57 +00007454 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007455 return (-1);
7456 if (err != NULL)
7457 *err = ctxt->error;
7458 if (warn != NULL)
7459 *warn = ctxt->warning;
7460 if (ctx != NULL)
7461 *ctx = ctxt->userData;
7462 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007463}
7464
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007465#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007466
Daniel Veillard6eadf632003-01-23 18:29:16 +00007467/************************************************************************
7468 * *
7469 * Dump back a compiled form *
7470 * *
7471 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007472static void xmlRelaxNGDumpDefine(FILE * output,
7473 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007474
7475/**
7476 * xmlRelaxNGDumpDefines:
7477 * @output: the file output
7478 * @defines: a list of define structures
7479 *
7480 * Dump a RelaxNG structure back
7481 */
7482static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007483xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7484{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007485 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007486 xmlRelaxNGDumpDefine(output, defines);
7487 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007488 }
7489}
7490
7491/**
7492 * xmlRelaxNGDumpDefine:
7493 * @output: the file output
7494 * @define: a define structure
7495 *
7496 * Dump a RelaxNG structure back
7497 */
7498static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007499xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7500{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007501 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007502 return;
7503 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007504 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007505 fprintf(output, "<empty/>\n");
7506 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007507 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007508 fprintf(output, "<notAllowed/>\n");
7509 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007510 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007511 fprintf(output, "<text/>\n");
7512 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007513 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007514 fprintf(output, "<element>\n");
7515 if (define->name != NULL) {
7516 fprintf(output, "<name");
7517 if (define->ns != NULL)
7518 fprintf(output, " ns=\"%s\"", define->ns);
7519 fprintf(output, ">%s</name>\n", define->name);
7520 }
7521 xmlRelaxNGDumpDefines(output, define->attrs);
7522 xmlRelaxNGDumpDefines(output, define->content);
7523 fprintf(output, "</element>\n");
7524 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007525 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007526 fprintf(output, "<list>\n");
7527 xmlRelaxNGDumpDefines(output, define->content);
7528 fprintf(output, "</list>\n");
7529 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007530 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007531 fprintf(output, "<oneOrMore>\n");
7532 xmlRelaxNGDumpDefines(output, define->content);
7533 fprintf(output, "</oneOrMore>\n");
7534 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007535 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007536 fprintf(output, "<zeroOrMore>\n");
7537 xmlRelaxNGDumpDefines(output, define->content);
7538 fprintf(output, "</zeroOrMore>\n");
7539 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007540 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007541 fprintf(output, "<choice>\n");
7542 xmlRelaxNGDumpDefines(output, define->content);
7543 fprintf(output, "</choice>\n");
7544 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007545 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007546 fprintf(output, "<group>\n");
7547 xmlRelaxNGDumpDefines(output, define->content);
7548 fprintf(output, "</group>\n");
7549 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007550 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007551 fprintf(output, "<interleave>\n");
7552 xmlRelaxNGDumpDefines(output, define->content);
7553 fprintf(output, "</interleave>\n");
7554 break;
7555 case XML_RELAXNG_OPTIONAL:
7556 fprintf(output, "<optional>\n");
7557 xmlRelaxNGDumpDefines(output, define->content);
7558 fprintf(output, "</optional>\n");
7559 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007560 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007561 fprintf(output, "<attribute>\n");
7562 xmlRelaxNGDumpDefines(output, define->content);
7563 fprintf(output, "</attribute>\n");
7564 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007565 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007566 fprintf(output, "<define");
7567 if (define->name != NULL)
7568 fprintf(output, " name=\"%s\"", define->name);
7569 fprintf(output, ">\n");
7570 xmlRelaxNGDumpDefines(output, define->content);
7571 fprintf(output, "</define>\n");
7572 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007573 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007574 fprintf(output, "<ref");
7575 if (define->name != NULL)
7576 fprintf(output, " name=\"%s\"", define->name);
7577 fprintf(output, ">\n");
7578 xmlRelaxNGDumpDefines(output, define->content);
7579 fprintf(output, "</ref>\n");
7580 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007581 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007582 fprintf(output, "<parentRef");
7583 if (define->name != NULL)
7584 fprintf(output, " name=\"%s\"", define->name);
7585 fprintf(output, ">\n");
7586 xmlRelaxNGDumpDefines(output, define->content);
7587 fprintf(output, "</parentRef>\n");
7588 break;
7589 case XML_RELAXNG_EXTERNALREF:
7590 fprintf(output, "<externalRef>");
7591 xmlRelaxNGDumpDefines(output, define->content);
7592 fprintf(output, "</externalRef>\n");
7593 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007594 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007595 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007596 TODO break;
7597 case XML_RELAXNG_START:
7598 case XML_RELAXNG_EXCEPT:
7599 case XML_RELAXNG_PARAM:
7600 TODO break;
7601 case XML_RELAXNG_NOOP:
7602 xmlRelaxNGDumpDefines(output, define->content);
7603 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007604 }
7605}
Daniel Veillard4c004142003-10-07 11:33:24 +00007606
Daniel Veillard6eadf632003-01-23 18:29:16 +00007607/**
7608 * xmlRelaxNGDumpGrammar:
7609 * @output: the file output
7610 * @grammar: a grammar structure
7611 * @top: is this a top grammar
7612 *
7613 * Dump a RelaxNG structure back
7614 */
7615static void
7616xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7617{
7618 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007619 return;
7620
Daniel Veillard6eadf632003-01-23 18:29:16 +00007621 fprintf(output, "<grammar");
7622 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007623 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7624 switch (grammar->combine) {
7625 case XML_RELAXNG_COMBINE_UNDEFINED:
7626 break;
7627 case XML_RELAXNG_COMBINE_CHOICE:
7628 fprintf(output, " combine=\"choice\"");
7629 break;
7630 case XML_RELAXNG_COMBINE_INTERLEAVE:
7631 fprintf(output, " combine=\"interleave\"");
7632 break;
7633 default:
7634 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007635 }
7636 fprintf(output, ">\n");
7637 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007638 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007639 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007640 fprintf(output, "<start>\n");
7641 xmlRelaxNGDumpDefine(output, grammar->start);
7642 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007643 }
7644 /* TODO ? Dump the defines ? */
7645 fprintf(output, "</grammar>\n");
7646}
7647
7648/**
7649 * xmlRelaxNGDump:
7650 * @output: the file output
7651 * @schema: a schema structure
7652 *
7653 * Dump a RelaxNG structure back
7654 */
7655void
7656xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7657{
7658 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007659 fprintf(output, "RelaxNG empty or failed to compile\n");
7660 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007661 }
7662 fprintf(output, "RelaxNG: ");
7663 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007664 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007665 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007666 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007667 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007668 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007669 }
7670 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007671 fprintf(output, "RelaxNG has no top grammar\n");
7672 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007673 }
7674 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7675}
7676
Daniel Veillardfebcca42003-02-16 15:44:18 +00007677/**
7678 * xmlRelaxNGDumpTree:
7679 * @output: the file output
7680 * @schema: a schema structure
7681 *
7682 * Dump the transformed RelaxNG tree.
7683 */
7684void
7685xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7686{
7687 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007688 fprintf(output, "RelaxNG empty or failed to compile\n");
7689 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007690 }
7691 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007692 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007693 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007694 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007695 }
7696}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007697#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007698
Daniel Veillard6eadf632003-01-23 18:29:16 +00007699/************************************************************************
7700 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007701 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007702 * *
7703 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007704static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7705 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007706
7707/**
7708 * xmlRelaxNGValidateCompiledCallback:
7709 * @exec: the regular expression instance
7710 * @token: the token which matched
7711 * @transdata: callback data, the define for the subelement if available
7712 @ @inputdata: callback data, the Relax NG validation context
7713 *
7714 * Handle the callback and if needed validate the element children.
7715 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007716static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007717xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007718 const xmlChar * token,
7719 void *transdata, void *inputdata)
7720{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007721 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7722 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7723 int ret;
7724
7725#ifdef DEBUG_COMPILE
7726 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007727 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007728#endif
7729 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007730 fprintf(stderr, "callback on %s missing context\n", token);
7731 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7732 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7733 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007734 }
7735 if (define == NULL) {
7736 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007737 return;
7738 fprintf(stderr, "callback on %s missing define\n", token);
7739 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7740 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7741 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007742 }
7743 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007744 fprintf(stderr, "callback on %s missing info\n", token);
7745 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7746 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7747 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007748 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007749 fprintf(stderr, "callback on %s define is not element\n", token);
7750 if (ctxt->errNo == XML_RELAXNG_OK)
7751 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7752 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007753 }
7754 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007755 if (ret != 0)
7756 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007757}
7758
7759/**
7760 * xmlRelaxNGValidateCompiledContent:
7761 * @ctxt: the RelaxNG validation context
7762 * @regexp: the regular expression as compiled
7763 * @content: list of children to test against the regexp
7764 *
7765 * Validate the content model of an element or start using the regexp
7766 *
7767 * Returns 0 in case of success, -1 in case of error.
7768 */
7769static int
7770xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007771 xmlRegexpPtr regexp, xmlNodePtr content)
7772{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007773 xmlRegExecCtxtPtr exec;
7774 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007775 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007776 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007777
7778 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007779 return (-1);
7780 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007781 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007782 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007783 cur = content;
7784 while (cur != NULL) {
7785 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007786 switch (cur->type) {
7787 case XML_TEXT_NODE:
7788 case XML_CDATA_SECTION_NODE:
7789 if (xmlIsBlankNode(cur))
7790 break;
7791 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7792 if (ret < 0) {
7793 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7794 cur->parent->name);
7795 }
7796 break;
7797 case XML_ELEMENT_NODE:
7798 if (cur->ns != NULL) {
7799 ret = xmlRegExecPushString2(exec, cur->name,
7800 cur->ns->href, ctxt);
7801 } else {
7802 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7803 }
7804 if (ret < 0) {
7805 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7806 }
7807 break;
7808 default:
7809 break;
7810 }
7811 if (ret < 0)
7812 break;
7813 /*
7814 * Switch to next element
7815 */
7816 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007817 }
7818 ret = xmlRegExecPushString(exec, NULL, NULL);
7819 if (ret == 1) {
7820 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007821 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007822 } else if (ret == 0) {
7823 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007824 * TODO: get some of the names needed to exit the current state of exec
7825 */
7826 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7827 ret = -1;
7828 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7829 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007830 } else {
7831 ret = -1;
7832 }
7833 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007834 /*
7835 * There might be content model errors outside of the pure
7836 * regexp validation, e.g. for attribute values.
7837 */
7838 if ((ret == 0) && (ctxt->perr != 0)) {
7839 ret = ctxt->perr;
7840 }
7841 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007842 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007843}
7844
7845/************************************************************************
7846 * *
7847 * Progressive validation of when possible *
7848 * *
7849 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007850static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7851 xmlRelaxNGDefinePtr defines);
7852static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
7853 int log);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007854static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007855
7856/**
7857 * xmlRelaxNGElemPush:
7858 * @ctxt: the validation context
7859 * @exec: the regexp runtime for the new content model
7860 *
7861 * Push a new regexp for the current node content model on the stack
7862 *
7863 * Returns 0 in case of success and -1 in case of error.
7864 */
7865static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007866xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7867{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007868 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007869 ctxt->elemMax = 10;
7870 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7871 sizeof
7872 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007873 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007874 xmlRngVErrMemory(ctxt, "validating\n");
7875 return (-1);
7876 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007877 }
7878 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007879 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007880 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007881 ctxt->elemMax *
7882 sizeof
7883 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007884 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007885 xmlRngVErrMemory(ctxt, "validating\n");
7886 return (-1);
7887 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007888 }
7889 ctxt->elemTab[ctxt->elemNr++] = exec;
7890 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007891 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007892}
7893
7894/**
7895 * xmlRelaxNGElemPop:
7896 * @ctxt: the validation context
7897 *
7898 * Pop the regexp of the current node content model from the stack
7899 *
7900 * Returns the exec or NULL if empty
7901 */
7902static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007903xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7904{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007905 xmlRegExecCtxtPtr ret;
7906
Daniel Veillard4c004142003-10-07 11:33:24 +00007907 if (ctxt->elemNr <= 0)
7908 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007909 ctxt->elemNr--;
7910 ret = ctxt->elemTab[ctxt->elemNr];
7911 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007912 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007913 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7914 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007915 ctxt->elem = NULL;
7916 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007917}
7918
7919/**
7920 * xmlRelaxNGValidateProgressiveCallback:
7921 * @exec: the regular expression instance
7922 * @token: the token which matched
7923 * @transdata: callback data, the define for the subelement if available
7924 @ @inputdata: callback data, the Relax NG validation context
7925 *
7926 * Handle the callback and if needed validate the element children.
7927 * some of the in/out informations are passed via the context in @inputdata.
7928 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007929static void
7930xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7931 ATTRIBUTE_UNUSED,
7932 const xmlChar * token,
7933 void *transdata, void *inputdata)
7934{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007935 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7936 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007937 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007938 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007939 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007940
7941#ifdef DEBUG_PROGRESSIVE
7942 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007943 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007944#endif
7945 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007946 fprintf(stderr, "callback on %s missing context\n", token);
7947 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007948 }
7949 ctxt->pstate = 1;
7950 if (define == NULL) {
7951 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007952 return;
7953 fprintf(stderr, "callback on %s missing define\n", token);
7954 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7955 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7956 ctxt->pstate = -1;
7957 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007958 }
7959 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007960 fprintf(stderr, "callback on %s missing info\n", token);
7961 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7962 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7963 ctxt->pstate = -1;
7964 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007965 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007966 fprintf(stderr, "callback on %s define is not element\n", token);
7967 if (ctxt->errNo == XML_RELAXNG_OK)
7968 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7969 ctxt->pstate = -1;
7970 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007971 }
7972 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007973 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7974 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7975 xmlRelaxNGDumpValidError(ctxt);
7976 ctxt->pstate = -1;
7977 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007978 }
7979 if (define->contModel == NULL) {
7980 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007981 * this node cannot be validated in a streamable fashion
7982 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00007983#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00007984 xmlGenericError(xmlGenericErrorContext,
7985 "Element '%s' validation is not streamable\n",
7986 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007987#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00007988 ctxt->pstate = 0;
7989 ctxt->pdef = define;
7990 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007991 }
7992 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00007993 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007994 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007995 ctxt->pstate = -1;
7996 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007997 }
7998 xmlRelaxNGElemPush(ctxt, exec);
7999
8000 /*
8001 * Validate the attributes part of the content.
8002 */
8003 state = xmlRelaxNGNewValidState(ctxt, node);
8004 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008005 ctxt->pstate = -1;
8006 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008007 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008008 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008009 ctxt->state = state;
8010 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008011 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8012 if (ret != 0) {
8013 ctxt->pstate = -1;
8014 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8015 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008016 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008017 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008018 ctxt->state->seq = NULL;
8019 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8020 if (ret != 0) {
8021 ctxt->pstate = -1;
8022 }
8023 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008024 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008025 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008026
8027 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008028
Daniel Veillard4c004142003-10-07 11:33:24 +00008029 for (i = 0; i < ctxt->states->nbState; i++) {
8030 state = ctxt->states->tabState[i];
8031 ctxt->state = state;
8032 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008033
Daniel Veillard4c004142003-10-07 11:33:24 +00008034 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8035 tmp = 0;
8036 break;
8037 }
8038 }
8039 if (tmp != 0) {
8040 /*
8041 * validation error, log the message for the "best" one
8042 */
8043 ctxt->flags |= FLAGS_IGNORABLE;
8044 xmlRelaxNGLogBestError(ctxt);
8045 }
8046 for (i = 0; i < ctxt->states->nbState; i++) {
8047 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8048 }
8049 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8050 ctxt->states = NULL;
8051 if ((ret == 0) && (tmp == -1))
8052 ctxt->pstate = -1;
8053 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008054 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008055 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008056 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8057 xmlRelaxNGDumpValidError(ctxt);
8058 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008059 }
8060 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008061}
8062
8063/**
8064 * xmlRelaxNGValidatePushElement:
8065 * @ctxt: the validation context
8066 * @doc: a document instance
8067 * @elem: an element instance
8068 *
8069 * Push a new element start on the RelaxNG validation stack.
8070 *
8071 * returns 1 if no validation problem was found or 0 if validating the
8072 * element requires a full node, and -1 in case of error.
8073 */
8074int
Daniel Veillard33300b42003-04-17 09:09:19 +00008075xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8076 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008077 xmlNodePtr elem)
8078{
8079 int ret = 1;
8080
8081 if ((ctxt == NULL) || (elem == NULL))
8082 return (-1);
8083
8084#ifdef DEBUG_PROGRESSIVE
8085 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8086#endif
8087 if (ctxt->elem == 0) {
8088 xmlRelaxNGPtr schema;
8089 xmlRelaxNGGrammarPtr grammar;
8090 xmlRegExecCtxtPtr exec;
8091 xmlRelaxNGDefinePtr define;
8092
8093 schema = ctxt->schema;
8094 if (schema == NULL) {
8095 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8096 return (-1);
8097 }
8098 grammar = schema->topgrammar;
8099 if ((grammar == NULL) || (grammar->start == NULL)) {
8100 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8101 return (-1);
8102 }
8103 define = grammar->start;
8104 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008105 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008106 return (0);
8107 }
8108 exec = xmlRegNewExecCtxt(define->contModel,
8109 xmlRelaxNGValidateProgressiveCallback,
8110 ctxt);
8111 if (exec == NULL) {
8112 return (-1);
8113 }
8114 xmlRelaxNGElemPush(ctxt, exec);
8115 }
8116 ctxt->pnode = elem;
8117 ctxt->pstate = 0;
8118 if (elem->ns != NULL) {
8119 ret =
8120 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8121 ctxt);
8122 } else {
8123 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8124 }
8125 if (ret < 0) {
8126 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8127 } else {
8128 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008129 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008130 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008131 ret = -1;
8132 else
8133 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008134 }
8135#ifdef DEBUG_PROGRESSIVE
8136 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008137 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8138 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008139#endif
8140 return (ret);
8141}
8142
8143/**
8144 * xmlRelaxNGValidatePushCData:
8145 * @ctxt: the RelaxNG validation context
8146 * @data: some character data read
8147 * @len: the lenght of the data
8148 *
8149 * check the CData parsed for validation in the current stack
8150 *
8151 * returns 1 if no validation problem was found or -1 otherwise
8152 */
8153int
8154xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008155 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008156{
8157 int ret = 1;
8158
8159 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8160 return (-1);
8161
8162#ifdef DEBUG_PROGRESSIVE
8163 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8164#endif
8165
8166 while (*data != 0) {
8167 if (!IS_BLANK(*data))
8168 break;
8169 data++;
8170 }
8171 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008172 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008173
8174 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8175 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008176 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008177#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008178 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008179#endif
8180
Daniel Veillard4c004142003-10-07 11:33:24 +00008181 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008182 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008183 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008184}
8185
8186/**
8187 * xmlRelaxNGValidatePopElement:
8188 * @ctxt: the RelaxNG validation context
8189 * @doc: a document instance
8190 * @elem: an element instance
8191 *
8192 * Pop the element end from the RelaxNG validation stack.
8193 *
8194 * returns 1 if no validation problem was found or 0 otherwise
8195 */
8196int
8197xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8198 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008199 xmlNodePtr elem)
8200{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008201 int ret;
8202 xmlRegExecCtxtPtr exec;
8203
Daniel Veillard4c004142003-10-07 11:33:24 +00008204 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8205 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008206#ifdef DEBUG_PROGRESSIVE
8207 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8208#endif
8209 /*
8210 * verify that we reached a terminal state of the content model.
8211 */
8212 exec = xmlRelaxNGElemPop(ctxt);
8213 ret = xmlRegExecPushString(exec, NULL, NULL);
8214 if (ret == 0) {
8215 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008216 * TODO: get some of the names needed to exit the current state of exec
8217 */
8218 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8219 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008220 } else if (ret < 0) {
8221 ret = -1;
8222 } else {
8223 ret = 1;
8224 }
8225 xmlRegFreeExecCtxt(exec);
8226#ifdef DEBUG_PROGRESSIVE
8227 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008228 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8229 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008230#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008231 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008232}
8233
8234/**
8235 * xmlRelaxNGValidateFullElement:
8236 * @ctxt: the validation context
8237 * @doc: a document instance
8238 * @elem: an element instance
8239 *
8240 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8241 * 0 and the content of the node has been expanded.
8242 *
8243 * returns 1 if no validation problem was found or -1 in case of error.
8244 */
8245int
Daniel Veillard33300b42003-04-17 09:09:19 +00008246xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8247 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008248 xmlNodePtr elem)
8249{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008250 int ret;
8251 xmlRelaxNGValidStatePtr state;
8252
Daniel Veillard4c004142003-10-07 11:33:24 +00008253 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8254 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008255#ifdef DEBUG_PROGRESSIVE
8256 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8257#endif
8258 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8259 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008260 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008261 }
8262 state->seq = elem;
8263 ctxt->state = state;
8264 ctxt->errNo = XML_RELAXNG_OK;
8265 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008266 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8267 ret = -1;
8268 else
8269 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008270 xmlRelaxNGFreeValidState(ctxt, state);
8271 ctxt->state = NULL;
8272#ifdef DEBUG_PROGRESSIVE
8273 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008274 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8275 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008276#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008277 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008278}
8279
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008280/************************************************************************
8281 * *
8282 * Generic interpreted validation implementation *
8283 * *
8284 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008285static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8286 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008287
8288/**
8289 * xmlRelaxNGSkipIgnored:
8290 * @ctxt: a schema validation context
8291 * @node: the top node.
8292 *
8293 * Skip ignorable nodes in that context
8294 *
8295 * Returns the new sibling or NULL in case of error.
8296 */
8297static xmlNodePtr
8298xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008299 xmlNodePtr node)
8300{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008301 /*
8302 * TODO complete and handle entities
8303 */
8304 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008305 ((node->type == XML_COMMENT_NODE) ||
8306 (node->type == XML_PI_NODE) ||
8307 (((node->type == XML_TEXT_NODE) ||
8308 (node->type == XML_CDATA_SECTION_NODE)) &&
8309 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8310 (IS_BLANK_NODE(node)))))) {
8311 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008312 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008313 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008314}
8315
8316/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008317 * xmlRelaxNGNormalize:
8318 * @ctxt: a schema validation context
8319 * @str: the string to normalize
8320 *
8321 * Implements the normalizeWhiteSpace( s ) function from
8322 * section 6.2.9 of the spec
8323 *
8324 * Returns the new string or NULL in case of error.
8325 */
8326static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008327xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8328{
Daniel Veillardedc91922003-01-26 00:52:04 +00008329 xmlChar *ret, *p;
8330 const xmlChar *tmp;
8331 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008332
Daniel Veillardedc91922003-01-26 00:52:04 +00008333 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008334 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008335 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008336 while (*tmp != 0)
8337 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008338 len = tmp - str;
8339
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008340 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008341 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008342 xmlRngVErrMemory(ctxt, "validating\n");
8343 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008344 }
8345 p = ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00008346 while (IS_BLANK(*str))
8347 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008348 while (*str != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008349 if (IS_BLANK(*str)) {
8350 while (IS_BLANK(*str))
8351 str++;
8352 if (*str == 0)
8353 break;
8354 *p++ = ' ';
8355 } else
8356 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008357 }
8358 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008359 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008360}
8361
8362/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008363 * xmlRelaxNGValidateDatatype:
8364 * @ctxt: a Relax-NG validation context
8365 * @value: the string value
8366 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008367 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008368 *
8369 * Validate the given value against the dataype
8370 *
8371 * Returns 0 if the validation succeeded or an error code.
8372 */
8373static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008374xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8375 const xmlChar * value,
8376 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8377{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008378 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008379 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008380 void *result = NULL;
8381 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008382
8383 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008384 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008385 }
8386 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008387 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008388 if ((define->attrs != NULL) &&
8389 (define->attrs->type == XML_RELAXNG_PARAM)) {
8390 ret =
8391 lib->check(lib->data, define->name, value, &result, node);
8392 } else {
8393 ret = lib->check(lib->data, define->name, value, NULL, node);
8394 }
8395 } else
8396 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008397 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008398 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8399 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8400 lib->freef(lib->data, result);
8401 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008402 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008403 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008404 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008405 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008406 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008407 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8408 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008409 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008410 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008411 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008412 if (lib->facet != NULL) {
8413 tmp = lib->facet(lib->data, define->name, cur->name,
8414 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008415 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008416 ret = -1;
8417 }
8418 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008419 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008420 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008421 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008422
Daniel Veillard4c004142003-10-07 11:33:24 +00008423 oldvalue = ctxt->state->value;
8424 oldendvalue = ctxt->state->endvalue;
8425 ctxt->state->value = (xmlChar *) value;
8426 ctxt->state->endvalue = NULL;
8427 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8428 ctxt->state->value = (xmlChar *) oldvalue;
8429 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008430 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008431 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008432 lib->freef(lib->data, result);
8433 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008434}
8435
8436/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008437 * xmlRelaxNGNextValue:
8438 * @ctxt: a Relax-NG validation context
8439 *
8440 * Skip to the next value when validating within a list
8441 *
8442 * Returns 0 if the operation succeeded or an error code.
8443 */
8444static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008445xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8446{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008447 xmlChar *cur;
8448
8449 cur = ctxt->state->value;
8450 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008451 ctxt->state->value = NULL;
8452 ctxt->state->endvalue = NULL;
8453 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008454 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008455 while (*cur != 0)
8456 cur++;
8457 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8458 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008459 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008460 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008461 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008462 ctxt->state->value = cur;
8463 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008464}
8465
8466/**
8467 * xmlRelaxNGValidateValueList:
8468 * @ctxt: a Relax-NG validation context
8469 * @defines: the list of definitions to verify
8470 *
8471 * Validate the given set of definitions for the current value
8472 *
8473 * Returns 0 if the validation succeeded or an error code.
8474 */
8475static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008476xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8477 xmlRelaxNGDefinePtr defines)
8478{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008479 int ret = 0;
8480
8481 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008482 ret = xmlRelaxNGValidateValue(ctxt, defines);
8483 if (ret != 0)
8484 break;
8485 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008486 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008487 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008488}
8489
8490/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008491 * xmlRelaxNGValidateValue:
8492 * @ctxt: a Relax-NG validation context
8493 * @define: the definition to verify
8494 *
8495 * Validate the given definition for the current value
8496 *
8497 * Returns 0 if the validation succeeded or an error code.
8498 */
8499static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008500xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8501 xmlRelaxNGDefinePtr define)
8502{
Daniel Veillardedc91922003-01-26 00:52:04 +00008503 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008504 xmlChar *value;
8505
8506 value = ctxt->state->value;
8507 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008508 case XML_RELAXNG_EMPTY:{
8509 if ((value != NULL) && (value[0] != 0)) {
8510 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008511
Daniel Veillard4c004142003-10-07 11:33:24 +00008512 while (IS_BLANK(value[idx]))
8513 idx++;
8514 if (value[idx] != 0)
8515 ret = -1;
8516 }
8517 break;
8518 }
8519 case XML_RELAXNG_TEXT:
8520 break;
8521 case XML_RELAXNG_VALUE:{
8522 if (!xmlStrEqual(value, define->value)) {
8523 if (define->name != NULL) {
8524 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008525
Daniel Veillard4c004142003-10-07 11:33:24 +00008526 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8527 if ((lib != NULL) && (lib->comp != NULL)) {
8528 ret = lib->comp(lib->data, define->name,
8529 define->value, define->node,
8530 (void *) define->attrs,
8531 value, ctxt->state->node);
8532 } else
8533 ret = -1;
8534 if (ret < 0) {
8535 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8536 define->name);
8537 return (-1);
8538 } else if (ret == 1) {
8539 ret = 0;
8540 } else {
8541 ret = -1;
8542 }
8543 } else {
8544 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008545
Daniel Veillard4c004142003-10-07 11:33:24 +00008546 /*
8547 * TODO: trivial optimizations are possible by
8548 * computing at compile-time
8549 */
8550 nval = xmlRelaxNGNormalize(ctxt, define->value);
8551 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008552
Daniel Veillard4c004142003-10-07 11:33:24 +00008553 if ((nval == NULL) || (nvalue == NULL) ||
8554 (!xmlStrEqual(nval, nvalue)))
8555 ret = -1;
8556 if (nval != NULL)
8557 xmlFree(nval);
8558 if (nvalue != NULL)
8559 xmlFree(nvalue);
8560 }
8561 }
8562 if (ret == 0)
8563 xmlRelaxNGNextValue(ctxt);
8564 break;
8565 }
8566 case XML_RELAXNG_DATATYPE:{
8567 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8568 ctxt->state->seq);
8569 if (ret == 0)
8570 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008571
Daniel Veillard4c004142003-10-07 11:33:24 +00008572 break;
8573 }
8574 case XML_RELAXNG_CHOICE:{
8575 xmlRelaxNGDefinePtr list = define->content;
8576 xmlChar *oldvalue;
8577
8578 oldflags = ctxt->flags;
8579 ctxt->flags |= FLAGS_IGNORABLE;
8580
8581 oldvalue = ctxt->state->value;
8582 while (list != NULL) {
8583 ret = xmlRelaxNGValidateValue(ctxt, list);
8584 if (ret == 0) {
8585 break;
8586 }
8587 ctxt->state->value = oldvalue;
8588 list = list->next;
8589 }
8590 ctxt->flags = oldflags;
8591 if (ret != 0) {
8592 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8593 xmlRelaxNGDumpValidError(ctxt);
8594 } else {
8595 if (ctxt->errNr > 0)
8596 xmlRelaxNGPopErrors(ctxt, 0);
8597 }
8598 if (ret == 0)
8599 xmlRelaxNGNextValue(ctxt);
8600 break;
8601 }
8602 case XML_RELAXNG_LIST:{
8603 xmlRelaxNGDefinePtr list = define->content;
8604 xmlChar *oldvalue, *oldend, *val, *cur;
8605
Daniel Veillard416589a2003-02-17 17:25:42 +00008606#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008607 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008608#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008609
Daniel Veillard4c004142003-10-07 11:33:24 +00008610 oldvalue = ctxt->state->value;
8611 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008612
Daniel Veillard4c004142003-10-07 11:33:24 +00008613 val = xmlStrdup(oldvalue);
8614 if (val == NULL) {
8615 val = xmlStrdup(BAD_CAST "");
8616 }
8617 if (val == NULL) {
8618 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8619 return (-1);
8620 }
8621 cur = val;
8622 while (*cur != 0) {
8623 if (IS_BLANK(*cur)) {
8624 *cur = 0;
8625 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008626#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008627 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008628#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008629 while (IS_BLANK(*cur))
8630 *cur++ = 0;
8631 } else
8632 cur++;
8633 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008634#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008635 xmlGenericError(xmlGenericErrorContext,
8636 "list value: '%s' found %d items\n",
8637 oldvalue, nb_values);
8638 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008639#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008640 ctxt->state->endvalue = cur;
8641 cur = val;
8642 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8643 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008644
Daniel Veillard4c004142003-10-07 11:33:24 +00008645 ctxt->state->value = cur;
8646
8647 while (list != NULL) {
8648 if (ctxt->state->value == ctxt->state->endvalue)
8649 ctxt->state->value = NULL;
8650 ret = xmlRelaxNGValidateValue(ctxt, list);
8651 if (ret != 0) {
8652#ifdef DEBUG_LIST
8653 xmlGenericError(xmlGenericErrorContext,
8654 "Failed to validate value: '%s' with %d rule\n",
8655 ctxt->state->value, nb_values);
8656#endif
8657 break;
8658 }
8659#ifdef DEBUG_LIST
8660 nb_values++;
8661#endif
8662 list = list->next;
8663 }
8664
8665 if ((ret == 0) && (ctxt->state->value != NULL) &&
8666 (ctxt->state->value != ctxt->state->endvalue)) {
8667 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8668 ctxt->state->value);
8669 ret = -1;
8670 }
8671 xmlFree(val);
8672 ctxt->state->value = oldvalue;
8673 ctxt->state->endvalue = oldend;
8674 break;
8675 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008676 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008677 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8678 if (ret != 0) {
8679 break;
8680 }
8681 /* no break on purpose */
8682 case XML_RELAXNG_ZEROORMORE:{
8683 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008684
Daniel Veillard4c004142003-10-07 11:33:24 +00008685 oldflags = ctxt->flags;
8686 ctxt->flags |= FLAGS_IGNORABLE;
8687 cur = ctxt->state->value;
8688 temp = NULL;
8689 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8690 (temp != cur)) {
8691 temp = cur;
8692 ret =
8693 xmlRelaxNGValidateValueList(ctxt, define->content);
8694 if (ret != 0) {
8695 ctxt->state->value = temp;
8696 ret = 0;
8697 break;
8698 }
8699 cur = ctxt->state->value;
8700 }
8701 ctxt->flags = oldflags;
8702 if (ret != 0) {
8703 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8704 xmlRelaxNGDumpValidError(ctxt);
8705 } else {
8706 if (ctxt->errNr > 0)
8707 xmlRelaxNGPopErrors(ctxt, 0);
8708 }
8709 break;
8710 }
8711 case XML_RELAXNG_EXCEPT:{
8712 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008713
Daniel Veillard4c004142003-10-07 11:33:24 +00008714 list = define->content;
8715 while (list != NULL) {
8716 ret = xmlRelaxNGValidateValue(ctxt, list);
8717 if (ret == 0) {
8718 ret = -1;
8719 break;
8720 } else
8721 ret = 0;
8722 list = list->next;
8723 }
8724 break;
8725 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008726 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008727 case XML_RELAXNG_GROUP:{
8728 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008729
Daniel Veillard4c004142003-10-07 11:33:24 +00008730 list = define->content;
8731 while (list != NULL) {
8732 ret = xmlRelaxNGValidateValue(ctxt, list);
8733 if (ret != 0) {
8734 ret = -1;
8735 break;
8736 } else
8737 ret = 0;
8738 list = list->next;
8739 }
8740 break;
8741 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008742 case XML_RELAXNG_REF:
8743 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008744 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8745 break;
8746 default:
8747 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008748 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008749 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008750}
8751
8752/**
8753 * xmlRelaxNGValidateValueContent:
8754 * @ctxt: a Relax-NG validation context
8755 * @defines: the list of definitions to verify
8756 *
8757 * Validate the given definitions for the current value
8758 *
8759 * Returns 0 if the validation succeeded or an error code.
8760 */
8761static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008762xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8763 xmlRelaxNGDefinePtr defines)
8764{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008765 int ret = 0;
8766
8767 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008768 ret = xmlRelaxNGValidateValue(ctxt, defines);
8769 if (ret != 0)
8770 break;
8771 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008772 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008773 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008774}
8775
8776/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008777 * xmlRelaxNGAttributeMatch:
8778 * @ctxt: a Relax-NG validation context
8779 * @define: the definition to check
8780 * @prop: the attribute
8781 *
8782 * Check if the attribute matches the definition nameClass
8783 *
8784 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8785 */
8786static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008787xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8788 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8789{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008790 int ret;
8791
8792 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008793 if (!xmlStrEqual(define->name, prop->name))
8794 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008795 }
8796 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008797 if (define->ns[0] == 0) {
8798 if (prop->ns != NULL)
8799 return (0);
8800 } else {
8801 if ((prop->ns == NULL) ||
8802 (!xmlStrEqual(define->ns, prop->ns->href)))
8803 return (0);
8804 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008805 }
8806 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008807 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008808 define = define->nameClass;
8809 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008810 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008811
Daniel Veillard4c004142003-10-07 11:33:24 +00008812 list = define->content;
8813 while (list != NULL) {
8814 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8815 if (ret == 1)
8816 return (0);
8817 if (ret < 0)
8818 return (ret);
8819 list = list->next;
8820 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008821 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008822 TODO}
8823 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008824}
8825
8826/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008827 * xmlRelaxNGValidateAttribute:
8828 * @ctxt: a Relax-NG validation context
8829 * @define: the definition to verify
8830 *
8831 * Validate the given attribute definition for that node
8832 *
8833 * Returns 0 if the validation succeeded or an error code.
8834 */
8835static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008836xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8837 xmlRelaxNGDefinePtr define)
8838{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008839 int ret = 0, i;
8840 xmlChar *value, *oldvalue;
8841 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008842 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008843
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008844 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008845 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008846 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008847 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8848 tmp = ctxt->state->attrs[i];
8849 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8850 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8851 (tmp->ns == NULL)) ||
8852 ((tmp->ns != NULL) &&
8853 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8854 prop = tmp;
8855 break;
8856 }
8857 }
8858 }
8859 if (prop != NULL) {
8860 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8861 oldvalue = ctxt->state->value;
8862 oldseq = ctxt->state->seq;
8863 ctxt->state->seq = (xmlNodePtr) prop;
8864 ctxt->state->value = value;
8865 ctxt->state->endvalue = NULL;
8866 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8867 if (ctxt->state->value != NULL)
8868 value = ctxt->state->value;
8869 if (value != NULL)
8870 xmlFree(value);
8871 ctxt->state->value = oldvalue;
8872 ctxt->state->seq = oldseq;
8873 if (ret == 0) {
8874 /*
8875 * flag the attribute as processed
8876 */
8877 ctxt->state->attrs[i] = NULL;
8878 ctxt->state->nbAttrLeft--;
8879 }
8880 } else {
8881 ret = -1;
8882 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008883#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008884 xmlGenericError(xmlGenericErrorContext,
8885 "xmlRelaxNGValidateAttribute(%s): %d\n",
8886 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008887#endif
8888 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008889 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8890 tmp = ctxt->state->attrs[i];
8891 if ((tmp != NULL) &&
8892 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8893 prop = tmp;
8894 break;
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 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8904 if (ctxt->state->value != NULL)
8905 value = ctxt->state->value;
8906 if (value != NULL)
8907 xmlFree(value);
8908 ctxt->state->value = oldvalue;
8909 ctxt->state->seq = oldseq;
8910 if (ret == 0) {
8911 /*
8912 * flag the attribute as processed
8913 */
8914 ctxt->state->attrs[i] = NULL;
8915 ctxt->state->nbAttrLeft--;
8916 }
8917 } else {
8918 ret = -1;
8919 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008920#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008921 if (define->ns != NULL) {
8922 xmlGenericError(xmlGenericErrorContext,
8923 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8924 define->ns, ret);
8925 } else {
8926 xmlGenericError(xmlGenericErrorContext,
8927 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8928 ret);
8929 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008930#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008931 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008932
8933 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008934}
8935
8936/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008937 * xmlRelaxNGValidateAttributeList:
8938 * @ctxt: a Relax-NG validation context
8939 * @define: the list of definition to verify
8940 *
8941 * Validate the given node against the list of attribute definitions
8942 *
8943 * Returns 0 if the validation succeeded or an error code.
8944 */
8945static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008946xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8947 xmlRelaxNGDefinePtr defines)
8948{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008949 int ret = 0, res;
8950 int needmore = 0;
8951 xmlRelaxNGDefinePtr cur;
8952
8953 cur = defines;
8954 while (cur != NULL) {
8955 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008956 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8957 ret = -1;
8958 } else
8959 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008960 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008961 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008962 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00008963 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008964 cur = defines;
8965 while (cur != NULL) {
8966 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008967 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8968 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8969 if (res < 0)
8970 ret = -1;
8971 } else {
8972 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8973 return (-1);
8974 }
8975 if (res == -1) /* continues on -2 */
8976 break;
8977 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008978 cur = cur->next;
8979 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008980
8981 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008982}
8983
8984/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008985 * xmlRelaxNGNodeMatchesList:
8986 * @node: the node
8987 * @list: a NULL terminated array of definitions
8988 *
8989 * Check if a node can be matched by one of the definitions
8990 *
8991 * Returns 1 if matches 0 otherwise
8992 */
8993static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008994xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
8995{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008996 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008997 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008998
8999 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009000 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009001
9002 cur = list[i++];
9003 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009004 if ((node->type == XML_ELEMENT_NODE) &&
9005 (cur->type == XML_RELAXNG_ELEMENT)) {
9006 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9007 if (tmp == 1)
9008 return (1);
9009 } else if (((node->type == XML_TEXT_NODE) ||
9010 (node->type == XML_CDATA_SECTION_NODE)) &&
9011 (cur->type == XML_RELAXNG_TEXT)) {
9012 return (1);
9013 }
9014 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009015 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009016 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009017}
9018
9019/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009020 * xmlRelaxNGValidateInterleave:
9021 * @ctxt: a Relax-NG validation context
9022 * @define: the definition to verify
9023 *
9024 * Validate an interleave definition for a node.
9025 *
9026 * Returns 0 if the validation succeeded or an error code.
9027 */
9028static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009029xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9030 xmlRelaxNGDefinePtr define)
9031{
William M. Brack779af002003-08-01 15:55:39 +00009032 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009033 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009034 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009035
9036 xmlRelaxNGValidStatePtr oldstate;
9037 xmlRelaxNGPartitionPtr partitions;
9038 xmlRelaxNGInterleaveGroupPtr group = NULL;
9039 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9040 xmlNodePtr *list = NULL, *lasts = NULL;
9041
9042 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009043 partitions = (xmlRelaxNGPartitionPtr) define->data;
9044 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009045 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009046 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9047 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009048 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009049 /*
9050 * Optimizations for MIXED
9051 */
9052 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009053 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009054 ctxt->flags |= FLAGS_MIXED_CONTENT;
9055 if (nbgroups == 2) {
9056 /*
9057 * this is a pure <mixed> case
9058 */
9059 if (ctxt->state != NULL)
9060 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9061 ctxt->state->seq);
9062 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9063 ret = xmlRelaxNGValidateDefinition(ctxt,
9064 partitions->groups[1]->
9065 rule);
9066 else
9067 ret = xmlRelaxNGValidateDefinition(ctxt,
9068 partitions->groups[0]->
9069 rule);
9070 if (ret == 0) {
9071 if (ctxt->state != NULL)
9072 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9073 ctxt->state->
9074 seq);
9075 }
9076 ctxt->flags = oldflags;
9077 return (ret);
9078 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009079 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009080
9081 /*
9082 * Build arrays to store the first and last node of the chain
9083 * pertaining to each group
9084 */
9085 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9086 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009087 xmlRngVErrMemory(ctxt, "validating\n");
9088 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009089 }
9090 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9091 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9092 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009093 xmlRngVErrMemory(ctxt, "validating\n");
9094 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009095 }
9096 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9097
9098 /*
9099 * Walk the sequence of children finding the right group and
9100 * sorting them in sequences.
9101 */
9102 cur = ctxt->state->seq;
9103 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9104 start = cur;
9105 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009106 ctxt->state->seq = cur;
9107 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009108 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009109 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009110
Daniel Veillard4c004142003-10-07 11:33:24 +00009111 if ((cur->type == XML_TEXT_NODE) ||
9112 (cur->type == XML_CDATA_SECTION_NODE)) {
9113 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9114 NULL);
9115 } else if (cur->type == XML_ELEMENT_NODE) {
9116 if (cur->ns != NULL) {
9117 tmp = xmlHashLookup2(partitions->triage, cur->name,
9118 cur->ns->href);
9119 if (tmp == NULL)
9120 tmp = xmlHashLookup2(partitions->triage,
9121 BAD_CAST "#any",
9122 cur->ns->href);
9123 } else
9124 tmp =
9125 xmlHashLookup2(partitions->triage, cur->name,
9126 NULL);
9127 if (tmp == NULL)
9128 tmp =
9129 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9130 NULL);
9131 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009132
Daniel Veillard4c004142003-10-07 11:33:24 +00009133 if (tmp == NULL) {
9134 i = nbgroups;
9135 } else {
9136 i = ((long) tmp) - 1;
9137 if (partitions->flags & IS_NEEDCHECK) {
9138 group = partitions->groups[i];
9139 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9140 i = nbgroups;
9141 }
9142 }
9143 } else {
9144 for (i = 0; i < nbgroups; i++) {
9145 group = partitions->groups[i];
9146 if (group == NULL)
9147 continue;
9148 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9149 break;
9150 }
9151 }
9152 /*
9153 * We break as soon as an element not matched is found
9154 */
9155 if (i >= nbgroups) {
9156 break;
9157 }
9158 if (lasts[i] != NULL) {
9159 lasts[i]->next = cur;
9160 lasts[i] = cur;
9161 } else {
9162 list[i] = cur;
9163 lasts[i] = cur;
9164 }
9165 if (cur->next != NULL)
9166 lastchg = cur->next;
9167 else
9168 lastchg = cur;
9169 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009170 }
9171 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009172 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9173 ret = -1;
9174 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009175 }
9176 lastelem = cur;
9177 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009178 for (i = 0; i < nbgroups; i++) {
9179 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9180 group = partitions->groups[i];
9181 if (lasts[i] != NULL) {
9182 last = lasts[i]->next;
9183 lasts[i]->next = NULL;
9184 }
9185 ctxt->state->seq = list[i];
9186 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9187 if (ret != 0)
9188 break;
9189 if (ctxt->state != NULL) {
9190 cur = ctxt->state->seq;
9191 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9192 xmlRelaxNGFreeValidState(ctxt, oldstate);
9193 oldstate = ctxt->state;
9194 ctxt->state = NULL;
9195 if (cur != NULL) {
9196 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9197 ret = -1;
9198 ctxt->state = oldstate;
9199 goto done;
9200 }
9201 } else if (ctxt->states != NULL) {
9202 int j;
9203 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009204
Daniel Veillard4c004142003-10-07 11:33:24 +00009205 for (j = 0; j < ctxt->states->nbState; j++) {
9206 cur = ctxt->states->tabState[j]->seq;
9207 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9208 if (cur == NULL) {
9209 found = 1;
9210 break;
9211 }
9212 }
9213 if (ctxt->states->nbState > 0) {
9214 xmlRelaxNGFreeValidState(ctxt, oldstate);
9215 oldstate =
9216 ctxt->states->tabState[ctxt->states->nbState - 1];
9217 }
9218 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9219 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9220 }
9221 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9222 ctxt->states = NULL;
9223 if (found == 0) {
9224 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9225 ret = -1;
9226 ctxt->state = oldstate;
9227 goto done;
9228 }
9229 } else {
9230 ret = -1;
9231 break;
9232 }
9233 if (lasts[i] != NULL) {
9234 lasts[i]->next = last;
9235 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009236 }
9237 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009238 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009239 ctxt->state = oldstate;
9240 ctxt->state->seq = lastelem;
9241 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009242 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9243 ret = -1;
9244 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009245 }
9246
Daniel Veillard4c004142003-10-07 11:33:24 +00009247 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009248 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009249 /*
9250 * builds the next links chain from the prev one
9251 */
9252 cur = lastchg;
9253 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009254 if ((cur == start) || (cur->prev == NULL))
9255 break;
9256 cur->prev->next = cur;
9257 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009258 }
9259 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009260 if (ctxt->errNr > errNr)
9261 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009262 }
9263
9264 xmlFree(list);
9265 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009266 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009267}
9268
9269/**
9270 * xmlRelaxNGValidateDefinitionList:
9271 * @ctxt: a Relax-NG validation context
9272 * @define: the list of definition to verify
9273 *
9274 * Validate the given node content against the (list) of definitions
9275 *
9276 * Returns 0 if the validation succeeded or an error code.
9277 */
9278static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009279xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9280 xmlRelaxNGDefinePtr defines)
9281{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009282 int ret = 0, res;
9283
9284
Daniel Veillard952379b2003-03-17 15:37:12 +00009285 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009286 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9287 BAD_CAST "NULL definition list");
9288 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009289 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009290 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009291 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9292 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9293 if (res < 0)
9294 ret = -1;
9295 } else {
9296 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9297 return (-1);
9298 }
9299 if (res == -1) /* continues on -2 */
9300 break;
9301 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009302 }
9303
Daniel Veillard4c004142003-10-07 11:33:24 +00009304 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009305}
9306
9307/**
9308 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009309 * @ctxt: a Relax-NG validation context
9310 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009311 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009312 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009313 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009314 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009315 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009316 */
9317static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009318xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9319 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9320{
Daniel Veillard580ced82003-03-21 21:22:48 +00009321 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009322
Daniel Veillardfd573f12003-03-16 17:52:32 +00009323 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009324 if (!xmlStrEqual(elem->name, define->name)) {
9325 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9326 return (0);
9327 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009328 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009329 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009330 if (elem->ns == NULL) {
9331 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9332 return (0);
9333 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9334 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9335 elem->name, define->ns);
9336 return (0);
9337 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009338 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009339 (define->name == NULL)) {
9340 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9341 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009342 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009343 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9344 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009345 }
9346
9347 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009348 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009349
9350 define = define->nameClass;
9351 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009352 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009353
Daniel Veillard4c004142003-10-07 11:33:24 +00009354 if (ctxt != NULL) {
9355 oldflags = ctxt->flags;
9356 ctxt->flags |= FLAGS_IGNORABLE;
9357 }
9358
9359 list = define->content;
9360 while (list != NULL) {
9361 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9362 if (ret == 1) {
9363 if (ctxt != NULL)
9364 ctxt->flags = oldflags;
9365 return (0);
9366 }
9367 if (ret < 0) {
9368 if (ctxt != NULL)
9369 ctxt->flags = oldflags;
9370 return (ret);
9371 }
9372 list = list->next;
9373 }
9374 ret = 1;
9375 if (ctxt != NULL) {
9376 ctxt->flags = oldflags;
9377 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009378 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009379 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009380
Daniel Veillard4c004142003-10-07 11:33:24 +00009381 if (ctxt != NULL) {
9382 oldflags = ctxt->flags;
9383 ctxt->flags |= FLAGS_IGNORABLE;
9384 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009385
Daniel Veillard4c004142003-10-07 11:33:24 +00009386 list = define->nameClass;
9387 while (list != NULL) {
9388 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9389 if (ret == 1) {
9390 if (ctxt != NULL)
9391 ctxt->flags = oldflags;
9392 return (1);
9393 }
9394 if (ret < 0) {
9395 if (ctxt != NULL)
9396 ctxt->flags = oldflags;
9397 return (ret);
9398 }
9399 list = list->next;
9400 }
9401 if (ctxt != NULL) {
9402 if (ret != 0) {
9403 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9404 xmlRelaxNGDumpValidError(ctxt);
9405 } else {
9406 if (ctxt->errNr > 0)
9407 xmlRelaxNGPopErrors(ctxt, 0);
9408 }
9409 }
9410 ret = 0;
9411 if (ctxt != NULL) {
9412 ctxt->flags = oldflags;
9413 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009414 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009415 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009416 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009417 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009418}
9419
9420/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009421 * xmlRelaxNGBestState:
9422 * @ctxt: a Relax-NG validation context
9423 *
9424 * Find the "best" state in the ctxt->states list of states to report
9425 * errors about. I.e. a state with no element left in the child list
9426 * or the one with the less attributes left.
9427 * This is called only if a falidation error was detected
9428 *
9429 * Returns the index of the "best" state or -1 in case of error
9430 */
9431static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009432xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9433{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009434 xmlRelaxNGValidStatePtr state;
9435 int i, tmp;
9436 int best = -1;
9437 int value = 1000000;
9438
9439 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9440 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009441 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009442
Daniel Veillard4c004142003-10-07 11:33:24 +00009443 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009444 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009445 if (state == NULL)
9446 continue;
9447 if (state->seq != NULL) {
9448 if ((best == -1) || (value > 100000)) {
9449 value = 100000;
9450 best = i;
9451 }
9452 } else {
9453 tmp = state->nbAttrLeft;
9454 if ((best == -1) || (value > tmp)) {
9455 value = tmp;
9456 best = i;
9457 }
9458 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009459 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009460 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009461}
9462
9463/**
9464 * xmlRelaxNGLogBestError:
9465 * @ctxt: a Relax-NG validation context
9466 *
9467 * Find the "best" state in the ctxt->states list of states to report
9468 * errors about and log it.
9469 */
9470static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009471xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9472{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009473 int best;
9474
9475 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9476 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009477 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009478
9479 best = xmlRelaxNGBestState(ctxt);
9480 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009481 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009482
Daniel Veillard4c004142003-10-07 11:33:24 +00009483 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009484 }
9485}
9486
9487/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009488 * xmlRelaxNGValidateElementEnd:
9489 * @ctxt: a Relax-NG validation context
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009490 * @log: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009491 *
9492 * Validate the end of the element, implements check that
9493 * there is nothing left not consumed in the element content
9494 * or in the attribute list.
9495 *
9496 * Returns 0 if the validation succeeded or an error code.
9497 */
9498static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009499xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int log)
9500{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009501 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009502 xmlRelaxNGValidStatePtr state;
9503
9504 state = ctxt->state;
9505 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009506 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9507 if (state->seq != NULL) {
9508 if (log) {
9509 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9510 state->node->name, state->seq->name);
9511 }
9512 return (-1);
9513 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009514 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009515 for (i = 0; i < state->nbAttrs; i++) {
9516 if (state->attrs[i] != NULL) {
9517 if (log) {
9518 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9519 state->attrs[i]->name, state->node->name);
9520 }
9521 return (-1 - i);
9522 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009523 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009524 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009525}
9526
9527/**
9528 * xmlRelaxNGValidateState:
9529 * @ctxt: a Relax-NG validation context
9530 * @define: the definition to verify
9531 *
9532 * Validate the current state against the definition
9533 *
9534 * Returns 0 if the validation succeeded or an error code.
9535 */
9536static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009537xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9538 xmlRelaxNGDefinePtr define)
9539{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009540 xmlNodePtr node;
9541 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009542 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009543
9544 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009545 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9546 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009547 }
9548
9549 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009550 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009551 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009552 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009553 }
9554#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009555 for (i = 0; i < ctxt->depth; i++)
9556 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009557 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009558 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009559 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009560 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009561 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009562 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009563 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009564 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009565#endif
9566 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009567 switch (define->type) {
9568 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009569 node = xmlRelaxNGSkipIgnored(ctxt, node);
9570 ret = 0;
9571 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009572 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009573 ret = -1;
9574 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009575 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009576 while ((node != NULL) &&
9577 ((node->type == XML_TEXT_NODE) ||
9578 (node->type == XML_COMMENT_NODE) ||
9579 (node->type == XML_PI_NODE) ||
9580 (node->type == XML_CDATA_SECTION_NODE)))
9581 node = node->next;
9582 ctxt->state->seq = node;
9583 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009584 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009585 errNr = ctxt->errNr;
9586 node = xmlRelaxNGSkipIgnored(ctxt, node);
9587 if (node == NULL) {
9588 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9589 ret = -1;
9590 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9591 xmlRelaxNGDumpValidError(ctxt);
9592 break;
9593 }
9594 if (node->type != XML_ELEMENT_NODE) {
9595 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9596 ret = -1;
9597 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9598 xmlRelaxNGDumpValidError(ctxt);
9599 break;
9600 }
9601 /*
9602 * This node was already validated successfully against
9603 * this definition.
9604 */
9605 if (node->_private == define) {
9606 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9607 if (ctxt->errNr > errNr)
9608 xmlRelaxNGPopErrors(ctxt, errNr);
9609 if (ctxt->errNr != 0) {
9610 while ((ctxt->err != NULL) &&
9611 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9612 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9613 ||
9614 ((ctxt->err->err ==
9615 XML_RELAXNG_ERR_ELEMEXTRANS)
9616 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9617 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9618 || (ctxt->err->err ==
9619 XML_RELAXNG_ERR_NOTELEM)))
9620 xmlRelaxNGValidErrorPop(ctxt);
9621 }
9622 break;
9623 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009624
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009625 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9626 if (ret <= 0) {
9627 ret = -1;
9628 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9629 xmlRelaxNGDumpValidError(ctxt);
9630 break;
9631 }
9632 ret = 0;
9633 if (ctxt->errNr != 0) {
9634 if (ctxt->errNr > errNr)
9635 xmlRelaxNGPopErrors(ctxt, errNr);
9636 while ((ctxt->err != NULL) &&
9637 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9638 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9639 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9640 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9641 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9642 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9643 xmlRelaxNGValidErrorPop(ctxt);
9644 }
9645 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009646
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009647 oldflags = ctxt->flags;
9648 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9649 ctxt->flags -= FLAGS_MIXED_CONTENT;
9650 }
9651 state = xmlRelaxNGNewValidState(ctxt, node);
9652 if (state == NULL) {
9653 ret = -1;
9654 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9655 xmlRelaxNGDumpValidError(ctxt);
9656 break;
9657 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009658
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009659 oldstate = ctxt->state;
9660 ctxt->state = state;
9661 if (define->attrs != NULL) {
9662 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9663 if (tmp != 0) {
9664 ret = -1;
9665 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9666 }
9667 }
9668 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009669 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9670 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9671 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009672
Daniel Veillard4c004142003-10-07 11:33:24 +00009673 nstate = xmlRelaxNGNewValidState(ctxt, node);
9674 ctxt->state = nstate;
9675 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009676
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009677 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9678 define->contModel,
9679 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009680 nseq = ctxt->state->seq;
9681 ctxt->state = tmpstate;
9682 ctxt->states = tmpstates;
9683 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009684
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009685#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009686 xmlGenericError(xmlGenericErrorContext,
9687 "Validating content of '%s' : %d\n",
9688 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009689#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009690 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009691 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009692
9693 if (ctxt->states != NULL) {
9694 tmp = -1;
9695
Daniel Veillardce192eb2003-04-16 15:58:05 +00009696 for (i = 0; i < ctxt->states->nbState; i++) {
9697 state = ctxt->states->tabState[i];
9698 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009699 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009700
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009701 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009702 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009703 break;
9704 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009705 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009706 if (tmp != 0) {
9707 /*
9708 * validation error, log the message for the "best" one
9709 */
9710 ctxt->flags |= FLAGS_IGNORABLE;
9711 xmlRelaxNGLogBestError(ctxt);
9712 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009713 for (i = 0; i < ctxt->states->nbState; i++) {
9714 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009715 ctxt->states->
9716 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009717 }
9718 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9719 ctxt->flags = oldflags;
9720 ctxt->states = NULL;
9721 if ((ret == 0) && (tmp == -1))
9722 ret = -1;
9723 } else {
9724 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009725 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009726 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009727 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009728 xmlRelaxNGFreeValidState(ctxt, state);
9729 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009730 } else {
9731 if (define->content != NULL) {
9732 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009733 define->
9734 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009735 if (tmp != 0) {
9736 ret = -1;
9737 if (ctxt->state == NULL) {
9738 ctxt->state = oldstate;
9739 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9740 node->name);
9741 ctxt->state = NULL;
9742 } else {
9743 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9744 node->name);
9745 }
9746
9747 }
9748 }
9749 if (ctxt->states != NULL) {
9750 tmp = -1;
9751
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009752 for (i = 0; i < ctxt->states->nbState; i++) {
9753 state = ctxt->states->tabState[i];
9754 ctxt->state = state;
9755
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009756 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009757 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009758 break;
9759 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009760 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009761 if (tmp != 0) {
9762 /*
9763 * validation error, log the message for the "best" one
9764 */
9765 ctxt->flags |= FLAGS_IGNORABLE;
9766 xmlRelaxNGLogBestError(ctxt);
9767 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009768 for (i = 0; i < ctxt->states->nbState; i++) {
9769 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009770 ctxt->states->
9771 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009772 }
9773 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9774 ctxt->flags = oldflags;
9775 ctxt->states = NULL;
9776 if ((ret == 0) && (tmp == -1))
9777 ret = -1;
9778 } else {
9779 state = ctxt->state;
9780 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009781 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009782 xmlRelaxNGFreeValidState(ctxt, state);
9783 }
9784 }
9785 if (ret == 0) {
9786 node->_private = define;
9787 }
9788 ctxt->flags = oldflags;
9789 ctxt->state = oldstate;
9790 if (oldstate != NULL)
9791 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9792 if (ret != 0) {
9793 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9794 xmlRelaxNGDumpValidError(ctxt);
9795 ret = 0;
9796 } else {
9797 ret = -2;
9798 }
9799 } else {
9800 if (ctxt->errNr > errNr)
9801 xmlRelaxNGPopErrors(ctxt, errNr);
9802 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009803
9804#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009805 xmlGenericError(xmlGenericErrorContext,
9806 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9807 node->name, ret);
9808 if (oldstate == NULL)
9809 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9810 else if (oldstate->seq == NULL)
9811 xmlGenericError(xmlGenericErrorContext, ": done\n");
9812 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9813 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9814 oldstate->seq->name);
9815 else
9816 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9817 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009818#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009819 break;
9820 case XML_RELAXNG_OPTIONAL:{
9821 errNr = ctxt->errNr;
9822 oldflags = ctxt->flags;
9823 ctxt->flags |= FLAGS_IGNORABLE;
9824 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9825 ret =
9826 xmlRelaxNGValidateDefinitionList(ctxt,
9827 define->content);
9828 if (ret != 0) {
9829 if (ctxt->state != NULL)
9830 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9831 ctxt->state = oldstate;
9832 ctxt->flags = oldflags;
9833 ret = 0;
9834 if (ctxt->errNr > errNr)
9835 xmlRelaxNGPopErrors(ctxt, errNr);
9836 break;
9837 }
9838 if (ctxt->states != NULL) {
9839 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9840 } else {
9841 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9842 if (ctxt->states == NULL) {
9843 xmlRelaxNGFreeValidState(ctxt, oldstate);
9844 ctxt->flags = oldflags;
9845 ret = -1;
9846 if (ctxt->errNr > errNr)
9847 xmlRelaxNGPopErrors(ctxt, errNr);
9848 break;
9849 }
9850 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9851 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9852 ctxt->state = NULL;
9853 }
9854 ctxt->flags = oldflags;
9855 ret = 0;
9856 if (ctxt->errNr > errNr)
9857 xmlRelaxNGPopErrors(ctxt, errNr);
9858 break;
9859 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009860 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009861 errNr = ctxt->errNr;
9862 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9863 if (ret != 0) {
9864 break;
9865 }
9866 if (ctxt->errNr > errNr)
9867 xmlRelaxNGPopErrors(ctxt, errNr);
9868 /* no break on purpose */
9869 case XML_RELAXNG_ZEROORMORE:{
9870 int progress;
9871 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9872 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009873
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009874 errNr = ctxt->errNr;
9875 res = xmlRelaxNGNewStates(ctxt, 1);
9876 if (res == NULL) {
9877 ret = -1;
9878 break;
9879 }
9880 /*
9881 * All the input states are also exit states
9882 */
9883 if (ctxt->state != NULL) {
9884 xmlRelaxNGAddStates(ctxt, res,
9885 xmlRelaxNGCopyValidState(ctxt,
9886 ctxt->
9887 state));
9888 } else {
9889 for (j = 0; j < ctxt->states->nbState; j++) {
9890 xmlRelaxNGAddStates(ctxt, res,
9891 xmlRelaxNGCopyValidState(ctxt,
9892 ctxt->
9893 states->
9894 tabState
9895 [j]));
9896 }
9897 }
9898 oldflags = ctxt->flags;
9899 ctxt->flags |= FLAGS_IGNORABLE;
9900 do {
9901 progress = 0;
9902 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009903
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009904 if (ctxt->states != NULL) {
9905 states = ctxt->states;
9906 for (i = 0; i < states->nbState; i++) {
9907 ctxt->state = states->tabState[i];
9908 ctxt->states = NULL;
9909 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9910 define->
9911 content);
9912 if (ret == 0) {
9913 if (ctxt->state != NULL) {
9914 tmp = xmlRelaxNGAddStates(ctxt, res,
9915 ctxt->state);
9916 ctxt->state = NULL;
9917 if (tmp == 1)
9918 progress = 1;
9919 } else if (ctxt->states != NULL) {
9920 for (j = 0; j < ctxt->states->nbState;
9921 j++) {
9922 tmp =
9923 xmlRelaxNGAddStates(ctxt, res,
9924 ctxt->
9925 states->
9926 tabState
9927 [j]);
9928 if (tmp == 1)
9929 progress = 1;
9930 }
9931 xmlRelaxNGFreeStates(ctxt,
9932 ctxt->states);
9933 ctxt->states = NULL;
9934 }
9935 } else {
9936 if (ctxt->state != NULL) {
9937 xmlRelaxNGFreeValidState(ctxt,
9938 ctxt->state);
9939 ctxt->state = NULL;
9940 }
9941 }
9942 }
9943 } else {
9944 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9945 define->
9946 content);
9947 if (ret != 0) {
9948 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9949 ctxt->state = NULL;
9950 } else {
9951 base = res->nbState;
9952 if (ctxt->state != NULL) {
9953 tmp = xmlRelaxNGAddStates(ctxt, res,
9954 ctxt->state);
9955 ctxt->state = NULL;
9956 if (tmp == 1)
9957 progress = 1;
9958 } else if (ctxt->states != NULL) {
9959 for (j = 0; j < ctxt->states->nbState; j++) {
9960 tmp = xmlRelaxNGAddStates(ctxt, res,
9961 ctxt->
9962 states->
9963 tabState[j]);
9964 if (tmp == 1)
9965 progress = 1;
9966 }
9967 if (states == NULL) {
9968 states = ctxt->states;
9969 } else {
9970 xmlRelaxNGFreeStates(ctxt,
9971 ctxt->states);
9972 }
9973 ctxt->states = NULL;
9974 }
9975 }
9976 }
9977 if (progress) {
9978 /*
9979 * Collect all the new nodes added at that step
9980 * and make them the new node set
9981 */
9982 if (res->nbState - base == 1) {
9983 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9984 res->
9985 tabState
9986 [base]);
9987 } else {
9988 if (states == NULL) {
9989 xmlRelaxNGNewStates(ctxt,
9990 res->nbState - base);
9991 }
9992 states->nbState = 0;
9993 for (i = base; i < res->nbState; i++)
9994 xmlRelaxNGAddStates(ctxt, states,
9995 xmlRelaxNGCopyValidState
9996 (ctxt,
9997 res->tabState[i]));
9998 ctxt->states = states;
9999 }
10000 }
10001 } while (progress == 1);
10002 if (states != NULL) {
10003 xmlRelaxNGFreeStates(ctxt, states);
10004 }
10005 ctxt->states = res;
10006 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010007#if 0
10008 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010009 * errors may have to be propagated back...
10010 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010011 if (ctxt->errNr > errNr)
10012 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010013#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010014 ret = 0;
10015 break;
10016 }
10017 case XML_RELAXNG_CHOICE:{
10018 xmlRelaxNGDefinePtr list = NULL;
10019 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010020
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010021 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010022
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010023 errNr = ctxt->errNr;
10024 if ((define->dflags & IS_TRIABLE)
10025 && (define->data != NULL)) {
10026 xmlHashTablePtr triage =
10027 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010028
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010029 /*
10030 * Something we can optimize cleanly there is only one
10031 * possble branch out !
10032 */
10033 if (node == NULL) {
10034 ret = -1;
10035 break;
10036 }
10037 if ((node->type == XML_TEXT_NODE) ||
10038 (node->type == XML_CDATA_SECTION_NODE)) {
10039 list =
10040 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10041 } else if (node->type == XML_ELEMENT_NODE) {
10042 if (node->ns != NULL) {
10043 list = xmlHashLookup2(triage, node->name,
10044 node->ns->href);
10045 if (list == NULL)
10046 list =
10047 xmlHashLookup2(triage, BAD_CAST "#any",
10048 node->ns->href);
10049 } else
10050 list =
10051 xmlHashLookup2(triage, node->name, NULL);
10052 if (list == NULL)
10053 list =
10054 xmlHashLookup2(triage, BAD_CAST "#any",
10055 NULL);
10056 }
10057 if (list == NULL) {
10058 ret = -1;
10059 break;
10060 }
10061 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10062 if (ret == 0) {
10063 }
10064 break;
10065 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010066
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010067 list = define->content;
10068 oldflags = ctxt->flags;
10069 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010070
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010071 while (list != NULL) {
10072 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10073 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10074 if (ret == 0) {
10075 if (states == NULL) {
10076 states = xmlRelaxNGNewStates(ctxt, 1);
10077 }
10078 if (ctxt->state != NULL) {
10079 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10080 } else if (ctxt->states != NULL) {
10081 for (i = 0; i < ctxt->states->nbState; i++) {
10082 xmlRelaxNGAddStates(ctxt, states,
10083 ctxt->states->
10084 tabState[i]);
10085 }
10086 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10087 ctxt->states = NULL;
10088 }
10089 } else {
10090 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10091 }
10092 ctxt->state = oldstate;
10093 list = list->next;
10094 }
10095 if (states != NULL) {
10096 xmlRelaxNGFreeValidState(ctxt, oldstate);
10097 ctxt->states = states;
10098 ctxt->state = NULL;
10099 ret = 0;
10100 } else {
10101 ctxt->states = NULL;
10102 }
10103 ctxt->flags = oldflags;
10104 if (ret != 0) {
10105 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10106 xmlRelaxNGDumpValidError(ctxt);
10107 }
10108 } else {
10109 if (ctxt->errNr > errNr)
10110 xmlRelaxNGPopErrors(ctxt, errNr);
10111 }
10112 break;
10113 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010114 case XML_RELAXNG_DEF:
10115 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010116 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10117 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010118 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010119 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10120 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010121 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010122 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10123 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010124 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010125 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010126 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010127 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010128 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010129 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10130 break;
10131 case XML_RELAXNG_DATATYPE:{
10132 xmlNodePtr child;
10133 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010134
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010135 child = node;
10136 while (child != NULL) {
10137 if (child->type == XML_ELEMENT_NODE) {
10138 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10139 node->parent->name);
10140 ret = -1;
10141 break;
10142 } else if ((child->type == XML_TEXT_NODE) ||
10143 (child->type == XML_CDATA_SECTION_NODE)) {
10144 content = xmlStrcat(content, child->content);
10145 }
10146 /* TODO: handle entities ... */
10147 child = child->next;
10148 }
10149 if (ret == -1) {
10150 if (content != NULL)
10151 xmlFree(content);
10152 break;
10153 }
10154 if (content == NULL) {
10155 content = xmlStrdup(BAD_CAST "");
10156 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010157 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010158 ret = -1;
10159 break;
10160 }
10161 }
10162 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10163 ctxt->state->seq);
10164 if (ret == -1) {
10165 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10166 } else if (ret == 0) {
10167 ctxt->state->seq = NULL;
10168 }
10169 if (content != NULL)
10170 xmlFree(content);
10171 break;
10172 }
10173 case XML_RELAXNG_VALUE:{
10174 xmlChar *content = NULL;
10175 xmlChar *oldvalue;
10176 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010177
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010178 child = node;
10179 while (child != NULL) {
10180 if (child->type == XML_ELEMENT_NODE) {
10181 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10182 node->parent->name);
10183 ret = -1;
10184 break;
10185 } else if ((child->type == XML_TEXT_NODE) ||
10186 (child->type == XML_CDATA_SECTION_NODE)) {
10187 content = xmlStrcat(content, child->content);
10188 }
10189 /* TODO: handle entities ... */
10190 child = child->next;
10191 }
10192 if (ret == -1) {
10193 if (content != NULL)
10194 xmlFree(content);
10195 break;
10196 }
10197 if (content == NULL) {
10198 content = xmlStrdup(BAD_CAST "");
10199 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010200 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010201 ret = -1;
10202 break;
10203 }
10204 }
10205 oldvalue = ctxt->state->value;
10206 ctxt->state->value = content;
10207 ret = xmlRelaxNGValidateValue(ctxt, define);
10208 ctxt->state->value = oldvalue;
10209 if (ret == -1) {
10210 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10211 } else if (ret == 0) {
10212 ctxt->state->seq = NULL;
10213 }
10214 if (content != NULL)
10215 xmlFree(content);
10216 break;
10217 }
10218 case XML_RELAXNG_LIST:{
10219 xmlChar *content;
10220 xmlNodePtr child;
10221 xmlChar *oldvalue, *oldendvalue;
10222 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010223
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010224 /*
10225 * Make sure it's only text nodes
10226 */
10227
10228 content = NULL;
10229 child = node;
10230 while (child != NULL) {
10231 if (child->type == XML_ELEMENT_NODE) {
10232 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10233 node->parent->name);
10234 ret = -1;
10235 break;
10236 } else if ((child->type == XML_TEXT_NODE) ||
10237 (child->type == XML_CDATA_SECTION_NODE)) {
10238 content = xmlStrcat(content, child->content);
10239 }
10240 /* TODO: handle entities ... */
10241 child = child->next;
10242 }
10243 if (ret == -1) {
10244 if (content != NULL)
10245 xmlFree(content);
10246 break;
10247 }
10248 if (content == NULL) {
10249 content = xmlStrdup(BAD_CAST "");
10250 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010251 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010252 ret = -1;
10253 break;
10254 }
10255 }
10256 len = xmlStrlen(content);
10257 oldvalue = ctxt->state->value;
10258 oldendvalue = ctxt->state->endvalue;
10259 ctxt->state->value = content;
10260 ctxt->state->endvalue = content + len;
10261 ret = xmlRelaxNGValidateValue(ctxt, define);
10262 ctxt->state->value = oldvalue;
10263 ctxt->state->endvalue = oldendvalue;
10264 if (ret == -1) {
10265 VALID_ERR(XML_RELAXNG_ERR_LIST);
10266 } else if ((ret == 0) && (node != NULL)) {
10267 ctxt->state->seq = node->next;
10268 }
10269 if (content != NULL)
10270 xmlFree(content);
10271 break;
10272 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010273 case XML_RELAXNG_EXCEPT:
10274 case XML_RELAXNG_PARAM:
10275 TODO ret = -1;
10276 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010277 }
10278 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010279#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010280 for (i = 0; i < ctxt->depth; i++)
10281 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010282 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010283 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010284 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010285 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010286 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010287 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010288 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010289 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010290#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010291 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010292}
10293
10294/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010295 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010296 * @ctxt: a Relax-NG validation context
10297 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010298 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010299 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010300 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010301 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010302 */
10303static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010304xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10305 xmlRelaxNGDefinePtr define)
10306{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010307 xmlRelaxNGStatesPtr states, res;
10308 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010309
Daniel Veillardfd573f12003-03-16 17:52:32 +000010310 /*
10311 * We should NOT have both ctxt->state and ctxt->states
10312 */
10313 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010314 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10315 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010316 }
10317
10318 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010319 if (ctxt->states != NULL) {
10320 ctxt->state = ctxt->states->tabState[0];
10321 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10322 ctxt->states = NULL;
10323 }
10324 ret = xmlRelaxNGValidateState(ctxt, define);
10325 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10326 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10327 ctxt->state = NULL;
10328 }
10329 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10330 ctxt->state = ctxt->states->tabState[0];
10331 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10332 ctxt->states = NULL;
10333 }
10334 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010335 }
10336
10337 states = ctxt->states;
10338 ctxt->states = NULL;
10339 res = NULL;
10340 j = 0;
10341 oldflags = ctxt->flags;
10342 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010343 for (i = 0; i < states->nbState; i++) {
10344 ctxt->state = states->tabState[i];
10345 ctxt->states = NULL;
10346 ret = xmlRelaxNGValidateState(ctxt, define);
10347 /*
10348 * We should NOT have both ctxt->state and ctxt->states
10349 */
10350 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10351 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10352 ctxt->state = NULL;
10353 }
10354 if (ret == 0) {
10355 if (ctxt->states == NULL) {
10356 if (res != NULL) {
10357 /* add the state to the container */
10358 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10359 ctxt->state = NULL;
10360 } else {
10361 /* add the state directly in states */
10362 states->tabState[j++] = ctxt->state;
10363 ctxt->state = NULL;
10364 }
10365 } else {
10366 if (res == NULL) {
10367 /* make it the new container and copy other results */
10368 res = ctxt->states;
10369 ctxt->states = NULL;
10370 for (k = 0; k < j; k++)
10371 xmlRelaxNGAddStates(ctxt, res,
10372 states->tabState[k]);
10373 } else {
10374 /* add all the new results to res and reff the container */
10375 for (k = 0; k < ctxt->states->nbState; k++)
10376 xmlRelaxNGAddStates(ctxt, res,
10377 ctxt->states->tabState[k]);
10378 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10379 ctxt->states = NULL;
10380 }
10381 }
10382 } else {
10383 if (ctxt->state != NULL) {
10384 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10385 ctxt->state = NULL;
10386 } else if (ctxt->states != NULL) {
10387 for (k = 0; k < ctxt->states->nbState; k++)
10388 xmlRelaxNGFreeValidState(ctxt,
10389 ctxt->states->tabState[k]);
10390 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10391 ctxt->states = NULL;
10392 }
10393 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010394 }
10395 ctxt->flags = oldflags;
10396 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010397 xmlRelaxNGFreeStates(ctxt, states);
10398 ctxt->states = res;
10399 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010400 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010401 states->nbState = j;
10402 ctxt->states = states;
10403 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010404 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010405 ctxt->state = states->tabState[0];
10406 xmlRelaxNGFreeStates(ctxt, states);
10407 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010408 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010409 ret = -1;
10410 xmlRelaxNGFreeStates(ctxt, states);
10411 if (ctxt->states != NULL) {
10412 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10413 ctxt->states = NULL;
10414 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010415 }
10416 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010417 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10418 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010419 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010420 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010421}
10422
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010423/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010424 * xmlRelaxNGValidateDocument:
10425 * @ctxt: a Relax-NG validation context
10426 * @doc: the document
10427 *
10428 * Validate the given document
10429 *
10430 * Returns 0 if the validation succeeded or an error code.
10431 */
10432static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010433xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10434{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010435 int ret;
10436 xmlRelaxNGPtr schema;
10437 xmlRelaxNGGrammarPtr grammar;
10438 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010439 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010440
10441 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010442 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010443
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010444 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010445 schema = ctxt->schema;
10446 grammar = schema->topgrammar;
10447 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010448 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10449 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010450 }
10451 state = xmlRelaxNGNewValidState(ctxt, NULL);
10452 ctxt->state = state;
10453 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010454 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010455 state = ctxt->state;
10456 node = state->seq;
10457 node = xmlRelaxNGSkipIgnored(ctxt, node);
10458 if (node != NULL) {
10459 if (ret != -1) {
10460 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10461 ret = -1;
10462 }
10463 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010464 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010465 int i;
10466 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010467
Daniel Veillard4c004142003-10-07 11:33:24 +000010468 for (i = 0; i < ctxt->states->nbState; i++) {
10469 state = ctxt->states->tabState[i];
10470 node = state->seq;
10471 node = xmlRelaxNGSkipIgnored(ctxt, node);
10472 if (node == NULL)
10473 tmp = 0;
10474 xmlRelaxNGFreeValidState(ctxt, state);
10475 }
10476 if (tmp == -1) {
10477 if (ret != -1) {
10478 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10479 ret = -1;
10480 }
10481 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010482 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010483 if (ctxt->state != NULL) {
10484 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010485 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010486 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010487 if (ret != 0)
10488 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010489#ifdef DEBUG
10490 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010491 ctxt->error(ctxt->userData,
10492 "%d Extra error messages left on stack !\n",
10493 ctxt->errNr);
10494 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010495 }
10496#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010497 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010498 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010499
Daniel Veillard4c004142003-10-07 11:33:24 +000010500 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10501 vctxt.valid = 1;
10502 vctxt.error = ctxt->error;
10503 vctxt.warning = ctxt->warning;
10504 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010505
Daniel Veillard4c004142003-10-07 11:33:24 +000010506 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10507 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010508 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010509 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010510 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010511
Daniel Veillard4c004142003-10-07 11:33:24 +000010512 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010513}
10514
Daniel Veillardfd573f12003-03-16 17:52:32 +000010515/************************************************************************
10516 * *
10517 * Validation interfaces *
10518 * *
10519 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010520
Daniel Veillard6eadf632003-01-23 18:29:16 +000010521/**
10522 * xmlRelaxNGNewValidCtxt:
10523 * @schema: a precompiled XML RelaxNGs
10524 *
10525 * Create an XML RelaxNGs validation context based on the given schema
10526 *
10527 * Returns the validation context or NULL in case of error
10528 */
10529xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010530xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10531{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010532 xmlRelaxNGValidCtxtPtr ret;
10533
10534 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10535 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010536 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010537 return (NULL);
10538 }
10539 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10540 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010541 ret->error = xmlGenericError;
10542 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010543 ret->errNr = 0;
10544 ret->errMax = 0;
10545 ret->err = NULL;
10546 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010547 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010548 ret->states = NULL;
10549 ret->freeState = NULL;
10550 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010551 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010552 return (ret);
10553}
10554
10555/**
10556 * xmlRelaxNGFreeValidCtxt:
10557 * @ctxt: the schema validation context
10558 *
10559 * Free the resources associated to the schema validation context
10560 */
10561void
Daniel Veillard4c004142003-10-07 11:33:24 +000010562xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10563{
Daniel Veillard798024a2003-03-19 10:36:09 +000010564 int k;
10565
Daniel Veillard6eadf632003-01-23 18:29:16 +000010566 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010567 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010568 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010569 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010570 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010571 for (k = 0; k < ctxt->freeState->nbState; k++) {
10572 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10573 }
10574 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010575 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010576 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010577 for (k = 0; k < ctxt->freeStatesNr; k++) {
10578 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10579 }
10580 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010581 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010582 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010583 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010584 if (ctxt->elemTab != NULL) {
10585 xmlRegExecCtxtPtr exec;
10586
Daniel Veillard4c004142003-10-07 11:33:24 +000010587 exec = xmlRelaxNGElemPop(ctxt);
10588 while (exec != NULL) {
10589 xmlRegFreeExecCtxt(exec);
10590 exec = xmlRelaxNGElemPop(ctxt);
10591 }
10592 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010593 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010594 xmlFree(ctxt);
10595}
10596
10597/**
10598 * xmlRelaxNGSetValidErrors:
10599 * @ctxt: a Relax-NG validation context
10600 * @err: the error function
10601 * @warn: the warning function
10602 * @ctx: the functions context
10603 *
10604 * Set the error and warning callback informations
10605 */
10606void
10607xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010608 xmlRelaxNGValidityErrorFunc err,
10609 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10610{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010611 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010612 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010613 ctxt->error = err;
10614 ctxt->warning = warn;
10615 ctxt->userData = ctx;
10616}
10617
10618/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010619 * xmlRelaxNGGetValidErrors:
10620 * @ctxt: a Relax-NG validation context
10621 * @err: the error function result
10622 * @warn: the warning function result
10623 * @ctx: the functions context result
10624 *
10625 * Get the error and warning callback informations
10626 *
10627 * Returns -1 in case of error and 0 otherwise
10628 */
10629int
10630xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010631 xmlRelaxNGValidityErrorFunc * err,
10632 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10633{
Daniel Veillard409a8142003-07-18 15:16:57 +000010634 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010635 return (-1);
10636 if (err != NULL)
10637 *err = ctxt->error;
10638 if (warn != NULL)
10639 *warn = ctxt->warning;
10640 if (ctx != NULL)
10641 *ctx = ctxt->userData;
10642 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010643}
10644
10645/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010646 * xmlRelaxNGValidateDoc:
10647 * @ctxt: a Relax-NG validation context
10648 * @doc: a parsed document tree
10649 *
10650 * Validate a document tree in memory.
10651 *
10652 * Returns 0 if the document is valid, a positive error code
10653 * number otherwise and -1 in case of internal or API error.
10654 */
10655int
Daniel Veillard4c004142003-10-07 11:33:24 +000010656xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10657{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010658 int ret;
10659
10660 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010661 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010662
10663 ctxt->doc = doc;
10664
10665 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010666 /*
10667 * TODO: build error codes
10668 */
10669 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010670 return (1);
10671 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010672}
10673
10674#endif /* LIBXML_SCHEMAS_ENABLED */