blob: cdcc0798b1762ff064632e4b0bf9beb00cb592fd [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 Veillardc482e262003-02-26 14:48:48 +000049/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard71531f32003-02-05 13:19:53 +000050/* #define DEBUG_CONTENT 1 */
51/* #define DEBUG_TYPE 1 */
52/* #define DEBUG_VALID 1 */
Daniel Veillarde5b110b2003-02-04 14:43:39 +000053/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard416589a2003-02-17 17:25:42 +000054/* #define DEBUG_LIST 1 */
Daniel Veillard5add8682003-03-10 13:13:58 +000055/* #define DEBUG_INCLUDE */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000056/* #define DEBUG_ERROR 1 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000057/* #define DEBUG_COMPILE 1 */
Daniel Veillardf4e55762003-04-15 23:32:22 +000058/* #define DEBUG_PROGRESSIVE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000059
Daniel Veillard5f1946a2003-03-31 16:38:16 +000060#define MAX_ERROR 5
61
Daniel Veillard6eadf632003-01-23 18:29:16 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
67typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
68typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
69
70typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
71typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
72
Daniel Veillardd41f4f42003-01-29 21:07:52 +000073typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
74typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
75
Daniel Veillarda9d912d2003-02-01 17:43:10 +000076typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
77typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
78
Daniel Veillard6eadf632003-01-23 18:29:16 +000079typedef enum {
80 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
81 XML_RELAXNG_COMBINE_CHOICE, /* choice */
82 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
83} xmlRelaxNGCombine;
84
Daniel Veillard4c5cf702003-02-21 15:40:34 +000085typedef enum {
86 XML_RELAXNG_CONTENT_ERROR = -1,
87 XML_RELAXNG_CONTENT_EMPTY = 0,
88 XML_RELAXNG_CONTENT_SIMPLE,
89 XML_RELAXNG_CONTENT_COMPLEX
90} xmlRelaxNGContentType;
91
Daniel Veillard6eadf632003-01-23 18:29:16 +000092typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
93typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
94
95struct _xmlRelaxNGGrammar {
96 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
97 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
98 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
99 xmlRelaxNGDefinePtr start; /* <start> content */
100 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000101 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000102 xmlHashTablePtr defs; /* define* */
103 xmlHashTablePtr refs; /* references */
104};
105
106
Daniel Veillard6eadf632003-01-23 18:29:16 +0000107typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000108 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000109 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
110 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000111 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000112 XML_RELAXNG_TEXT, /* textual content */
113 XML_RELAXNG_ELEMENT, /* an element */
114 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000115 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000116 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
117 XML_RELAXNG_LIST, /* a list of patterns */
118 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
119 XML_RELAXNG_DEF, /* a definition */
120 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000121 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000122 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000123 XML_RELAXNG_OPTIONAL, /* optional patterns */
124 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000125 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
126 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
127 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000128 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000129 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000130} xmlRelaxNGType;
131
Daniel Veillard52b48c72003-04-13 19:53:42 +0000132#define IS_NULLABLE (1 << 0)
133#define IS_NOT_NULLABLE (1 << 1)
134#define IS_INDETERMINIST (1 << 2)
135#define IS_MIXED (1 << 3)
136#define IS_TRIABLE (1 << 4)
137#define IS_PROCESSED (1 << 5)
138#define IS_COMPILABLE (1 << 6)
139#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000140
Daniel Veillard6eadf632003-01-23 18:29:16 +0000141struct _xmlRelaxNGDefine {
142 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000143 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000144 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000145 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000146 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000147 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000148 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000149 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000150 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000151 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000152 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000153 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000154 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000155 short dflags; /* define related flags */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000156 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000157};
158
159/**
160 * _xmlRelaxNG:
161 *
162 * A RelaxNGs definition
163 */
164struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000165 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000166 xmlRelaxNGGrammarPtr topgrammar;
167 xmlDocPtr doc;
168
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000169 int idref; /* requires idref checking */
170
Daniel Veillard6eadf632003-01-23 18:29:16 +0000171 xmlHashTablePtr defs; /* define */
172 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000173 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
174 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000175 int defNr; /* number of defines used */
176 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000177
Daniel Veillard6eadf632003-01-23 18:29:16 +0000178};
179
Daniel Veillard77648bb2003-02-20 15:03:22 +0000180#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
181#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
182#define XML_RELAXNG_IN_LIST (1 << 2)
183#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
184#define XML_RELAXNG_IN_START (1 << 4)
185#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
186#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
187#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000188#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
189#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000190
191struct _xmlRelaxNGParserCtxt {
192 void *userData; /* user specific data block */
193 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
194 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000195 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000196
197 xmlRelaxNGPtr schema; /* The schema in use */
198 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000199 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200 int flags; /* parser flags */
201 int nbErrors; /* number of errors at parse time */
202 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000203 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000204 xmlRelaxNGDefinePtr def; /* the current define */
205
206 int nbInterleaves;
207 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000208
Daniel Veillardc482e262003-02-26 14:48:48 +0000209 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
210 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000211 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000212 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000213
Daniel Veillard419a7682003-02-03 23:22:49 +0000214 int defNr; /* number of defines used */
215 int defMax; /* number of defines aloocated */
216 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
217
Daniel Veillard6eadf632003-01-23 18:29:16 +0000218 const char *buffer;
219 int size;
220
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000221 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000222 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000223 int docNr; /* Depth of the parsing stack */
224 int docMax; /* Max depth of the parsing stack */
225 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000226
227 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000228 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000229 int incNr; /* Depth of the include parsing stack */
230 int incMax; /* Max depth of the parsing stack */
231 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000232
233 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000234
235 /* used to compile content models */
236 xmlAutomataPtr am; /* the automata */
237 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000238};
239
240#define FLAGS_IGNORABLE 1
241#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000242#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000243
244/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000245 * xmlRelaxNGInterleaveGroup:
246 *
247 * A RelaxNGs partition set associated to lists of definitions
248 */
249typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
250typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
251struct _xmlRelaxNGInterleaveGroup {
252 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
253 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000254 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000255};
256
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000257#define IS_DETERMINIST 1
258#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000259/**
260 * xmlRelaxNGPartitions:
261 *
262 * A RelaxNGs partition associated to an interleave group
263 */
264typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
265typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
266struct _xmlRelaxNGPartition {
267 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000268 xmlHashTablePtr triage; /* hash table used to direct nodes to the
269 right group when possible */
270 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000271 xmlRelaxNGInterleaveGroupPtr *groups;
272};
273
274/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000275 * xmlRelaxNGValidState:
276 *
277 * A RelaxNGs validation state
278 */
279#define MAX_ATTR 20
280typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
281typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
282struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000283 xmlNodePtr node; /* the current node */
284 xmlNodePtr seq; /* the sequence of children left to validate */
285 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000286 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000287 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000288 xmlChar *value; /* the value when operating on string */
289 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000290 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000291};
292
293/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000294 * xmlRelaxNGStates:
295 *
296 * A RelaxNGs container for validation state
297 */
298typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
299typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
300struct _xmlRelaxNGStates {
301 int nbState; /* the number of states */
302 int maxState; /* the size of the array */
303 xmlRelaxNGValidStatePtr *tabState;
304};
305
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000306#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000307/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000308 * xmlRelaxNGValidError:
309 *
310 * A RelaxNGs validation error
311 */
312typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
313typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
314struct _xmlRelaxNGValidError {
315 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000316 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000317 xmlNodePtr node; /* the current node */
318 xmlNodePtr seq; /* the current child */
319 const xmlChar * arg1; /* first arg */
320 const xmlChar * arg2; /* second arg */
321};
322
323/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000324 * xmlRelaxNGValidCtxt:
325 *
326 * A RelaxNGs validation context
327 */
328
329struct _xmlRelaxNGValidCtxt {
330 void *userData; /* user specific data block */
331 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
332 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
333
334 xmlRelaxNGPtr schema; /* The schema in use */
335 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000336 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000337 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000338 int idref; /* requires idref checking */
Daniel Veillarda507fbf2003-03-31 16:09:37 +0000339 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000340
341 /*
342 * Errors accumulated in branches may have to be stacked to be
343 * provided back when it's sure they affect validation.
344 */
345 xmlRelaxNGValidErrorPtr err; /* Last error */
346 int errNr; /* Depth of the error stack */
347 int errMax; /* Max depth of the error stack */
348 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000349
Daniel Veillardfd573f12003-03-16 17:52:32 +0000350 xmlRelaxNGValidStatePtr state; /* the current validation state */
351 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000352
353 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
354 int freeStatesNr;
355 int freeStatesMax;
356 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000357
358 /*
359 * This is used for "progressive" validation
360 */
361 xmlRegExecCtxtPtr elem; /* the current element regexp */
362 int elemNr; /* the number of element validated */
363 int elemMax; /* the max depth of elements */
364 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
365 int pstate; /* progressive state */
366 xmlNodePtr pnode; /* the current node */
367 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000368};
369
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000370/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000371 * xmlRelaxNGInclude:
372 *
373 * Structure associated to a RelaxNGs document element
374 */
375struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000376 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000377 xmlChar *href; /* the normalized href value */
378 xmlDocPtr doc; /* the associated XML document */
379 xmlRelaxNGDefinePtr content;/* the definitions */
380 xmlRelaxNGPtr schema; /* the schema */
381};
382
383/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000384 * xmlRelaxNGDocument:
385 *
386 * Structure associated to a RelaxNGs document element
387 */
388struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000389 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000390 xmlChar *href; /* the normalized href value */
391 xmlDocPtr doc; /* the associated XML document */
392 xmlRelaxNGDefinePtr content;/* the definitions */
393 xmlRelaxNGPtr schema; /* the schema */
394};
395
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000396
Daniel Veillard6eadf632003-01-23 18:29:16 +0000397/************************************************************************
398 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000399 * Preliminary type checking interfaces *
400 * *
401 ************************************************************************/
402/**
403 * xmlRelaxNGTypeHave:
404 * @data: data needed for the library
405 * @type: the type name
406 * @value: the value to check
407 *
408 * Function provided by a type library to check if a type is exported
409 *
410 * Returns 1 if yes, 0 if no and -1 in case of error.
411 */
412typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
413
414/**
415 * xmlRelaxNGTypeCheck:
416 * @data: data needed for the library
417 * @type: the type name
418 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000420 *
421 * Function provided by a type library to check if a value match a type
422 *
423 * Returns 1 if yes, 0 if no and -1 in case of error.
424 */
425typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000426 const xmlChar *value, void **result,
427 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000428
429/**
430 * xmlRelaxNGFacetCheck:
431 * @data: data needed for the library
432 * @type: the type name
433 * @facet: the facet name
434 * @val: the facet value
435 * @strval: the string value
436 * @value: the value to check
437 *
438 * Function provided by a type library to check a value facet
439 *
440 * Returns 1 if yes, 0 if no and -1 in case of error.
441 */
442typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
443 const xmlChar *facet, const xmlChar *val,
444 const xmlChar *strval, void *value);
445
446/**
447 * xmlRelaxNGTypeFree:
448 * @data: data needed for the library
449 * @result: the value to free
450 *
451 * Function provided by a type library to free a returned result
452 */
453typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000454
455/**
456 * xmlRelaxNGTypeCompare:
457 * @data: data needed for the library
458 * @type: the type name
459 * @value1: the first value
460 * @value2: the second value
461 *
462 * Function provided by a type library to compare two values accordingly
463 * to a type.
464 *
465 * Returns 1 if yes, 0 if no and -1 in case of error.
466 */
467typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
468 const xmlChar *value1,
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000469 xmlNodePtr ctxt1,
470 void *comp1,
471 const xmlChar *value2,
472 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000473typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
474typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
475struct _xmlRelaxNGTypeLibrary {
476 const xmlChar *namespace; /* the datatypeLibrary value */
477 void *data; /* data needed for the library */
478 xmlRelaxNGTypeHave have; /* the export function */
479 xmlRelaxNGTypeCheck check; /* the checking function */
480 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000481 xmlRelaxNGFacetCheck facet; /* the facet check function */
482 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000483};
484
485/************************************************************************
486 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000487 * Allocation functions *
488 * *
489 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000490static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
491static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000492static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000493static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000494static int xmlRelaxNGEqualValidState(
495 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
496 xmlRelaxNGValidStatePtr state1,
497 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000498static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
499 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000500
501/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000502 * xmlRelaxNGFreeDocument:
503 * @docu: a document structure
504 *
505 * Deallocate a RelaxNG document structure.
506 */
507static void
508xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
509{
510 if (docu == NULL)
511 return;
512
513 if (docu->href != NULL)
514 xmlFree(docu->href);
515 if (docu->doc != NULL)
516 xmlFreeDoc(docu->doc);
517 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000518 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000519 xmlFree(docu);
520}
521
522/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000523 * xmlRelaxNGFreeDocumentList:
524 * @docu: a list of document structure
525 *
526 * Deallocate a RelaxNG document structures.
527 */
528static void
529xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
530{
531 xmlRelaxNGDocumentPtr next;
532 while (docu != NULL) {
533 next = docu->next;
534 xmlRelaxNGFreeDocument(docu);
535 docu = next;
536 }
537}
538
539/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000540 * xmlRelaxNGFreeInclude:
541 * @incl: a include structure
542 *
543 * Deallocate a RelaxNG include structure.
544 */
545static void
546xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
547{
548 if (incl == NULL)
549 return;
550
551 if (incl->href != NULL)
552 xmlFree(incl->href);
553 if (incl->doc != NULL)
554 xmlFreeDoc(incl->doc);
555 if (incl->schema != NULL)
556 xmlRelaxNGFree(incl->schema);
557 xmlFree(incl);
558}
559
560/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000561 * xmlRelaxNGFreeIncludeList:
562 * @incl: a include structure list
563 *
564 * Deallocate a RelaxNG include structure.
565 */
566static void
567xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
568{
569 xmlRelaxNGIncludePtr next;
570 while (incl != NULL) {
571 next = incl->next;
572 xmlRelaxNGFreeInclude(incl);
573 incl = next;
574 }
575}
576
577/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000578 * xmlRelaxNGNewRelaxNG:
579 * @ctxt: a Relax-NG validation context (optional)
580 *
581 * Allocate a new RelaxNG structure.
582 *
583 * Returns the newly allocated structure or NULL in case or error
584 */
585static xmlRelaxNGPtr
586xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
587{
588 xmlRelaxNGPtr ret;
589
590 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
591 if (ret == NULL) {
592 if ((ctxt != NULL) && (ctxt->error != NULL))
593 ctxt->error(ctxt->userData, "Out of memory\n");
594 ctxt->nbErrors++;
595 return (NULL);
596 }
597 memset(ret, 0, sizeof(xmlRelaxNG));
598
599 return (ret);
600}
601
602/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000603 * xmlRelaxNGFreeInnerSchema:
604 * @schema: a schema structure
605 *
606 * Deallocate a RelaxNG schema structure.
607 */
608static void
609xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
610{
611 if (schema == NULL)
612 return;
613
614 if (schema->doc != NULL)
615 xmlFreeDoc(schema->doc);
616 if (schema->defTab != NULL) {
617 int i;
618
619 for (i = 0;i < schema->defNr;i++)
620 xmlRelaxNGFreeDefine(schema->defTab[i]);
621 xmlFree(schema->defTab);
622 }
623
624 xmlFree(schema);
625}
626
627/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000628 * xmlRelaxNGFree:
629 * @schema: a schema structure
630 *
631 * Deallocate a RelaxNG structure.
632 */
633void
634xmlRelaxNGFree(xmlRelaxNGPtr schema)
635{
636 if (schema == NULL)
637 return;
638
Daniel Veillard6eadf632003-01-23 18:29:16 +0000639 if (schema->topgrammar != NULL)
640 xmlRelaxNGFreeGrammar(schema->topgrammar);
641 if (schema->doc != NULL)
642 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000643 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000644 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000645 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000646 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000647 if (schema->defTab != NULL) {
648 int i;
649
650 for (i = 0;i < schema->defNr;i++)
651 xmlRelaxNGFreeDefine(schema->defTab[i]);
652 xmlFree(schema->defTab);
653 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000654
655 xmlFree(schema);
656}
657
658/**
659 * xmlRelaxNGNewGrammar:
660 * @ctxt: a Relax-NG validation context (optional)
661 *
662 * Allocate a new RelaxNG grammar.
663 *
664 * Returns the newly allocated structure or NULL in case or error
665 */
666static xmlRelaxNGGrammarPtr
667xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
668{
669 xmlRelaxNGGrammarPtr ret;
670
671 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
672 if (ret == NULL) {
673 if ((ctxt != NULL) && (ctxt->error != NULL))
674 ctxt->error(ctxt->userData, "Out of memory\n");
675 ctxt->nbErrors++;
676 return (NULL);
677 }
678 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
679
680 return (ret);
681}
682
683/**
684 * xmlRelaxNGFreeGrammar:
685 * @grammar: a grammar structure
686 *
687 * Deallocate a RelaxNG grammar structure.
688 */
689static void
690xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
691{
692 if (grammar == NULL)
693 return;
694
Daniel Veillardc482e262003-02-26 14:48:48 +0000695 if (grammar->children != NULL) {
696 xmlRelaxNGFreeGrammar(grammar->children);
697 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000698 if (grammar->next != NULL) {
699 xmlRelaxNGFreeGrammar(grammar->next);
700 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000701 if (grammar->refs != NULL) {
702 xmlHashFree(grammar->refs, NULL);
703 }
704 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000705 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000706 }
707
708 xmlFree(grammar);
709}
710
711/**
712 * xmlRelaxNGNewDefine:
713 * @ctxt: a Relax-NG validation context
714 * @node: the node in the input document.
715 *
716 * Allocate a new RelaxNG define.
717 *
718 * Returns the newly allocated structure or NULL in case or error
719 */
720static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000721xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000722{
723 xmlRelaxNGDefinePtr ret;
724
Daniel Veillard419a7682003-02-03 23:22:49 +0000725 if (ctxt->defMax == 0) {
726 ctxt->defMax = 16;
727 ctxt->defNr = 0;
728 ctxt->defTab = (xmlRelaxNGDefinePtr *)
729 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
730 if (ctxt->defTab == NULL) {
731 if ((ctxt != NULL) && (ctxt->error != NULL))
732 ctxt->error(ctxt->userData, "Out of memory\n");
733 ctxt->nbErrors++;
734 return (NULL);
735 }
736 } else if (ctxt->defMax <= ctxt->defNr) {
737 xmlRelaxNGDefinePtr *tmp;
738 ctxt->defMax *= 2;
739 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
740 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
741 if (tmp == NULL) {
742 if ((ctxt != NULL) && (ctxt->error != NULL))
743 ctxt->error(ctxt->userData, "Out of memory\n");
744 ctxt->nbErrors++;
745 return (NULL);
746 }
747 ctxt->defTab = tmp;
748 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000749 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
750 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000751 if ((ctxt != NULL) && (ctxt->error != NULL))
752 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000753 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000754 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000755 }
756 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000757 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000758 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000759 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000760 return (ret);
761}
762
763/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000764 * xmlRelaxNGFreePartition:
765 * @partitions: a partition set structure
766 *
767 * Deallocate RelaxNG partition set structures.
768 */
769static void
770xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
771 xmlRelaxNGInterleaveGroupPtr group;
772 int j;
773
774 if (partitions != NULL) {
775 if (partitions->groups != NULL) {
776 for (j = 0;j < partitions->nbgroups;j++) {
777 group = partitions->groups[j];
778 if (group != NULL) {
779 if (group->defs != NULL)
780 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000781 if (group->attrs != NULL)
782 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000783 xmlFree(group);
784 }
785 }
786 xmlFree(partitions->groups);
787 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000788 if (partitions->triage != NULL) {
789 xmlHashFree(partitions->triage, NULL);
790 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000791 xmlFree(partitions);
792 }
793}
794/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000795 * xmlRelaxNGFreeDefine:
796 * @define: a define structure
797 *
798 * Deallocate a RelaxNG define structure.
799 */
800static void
801xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
802{
803 if (define == NULL)
804 return;
805
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000806 if ((define->type == XML_RELAXNG_VALUE) &&
807 (define->attrs != NULL)) {
808 xmlRelaxNGTypeLibraryPtr lib;
809
810 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
811 if ((lib != NULL) && (lib->freef != NULL))
812 lib->freef(lib->data, (void *) define->attrs);
813 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000814 if ((define->data != NULL) &&
815 (define->type == XML_RELAXNG_INTERLEAVE))
816 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000817 if ((define->data != NULL) &&
818 (define->type == XML_RELAXNG_CHOICE))
819 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000820 if (define->name != NULL)
821 xmlFree(define->name);
822 if (define->ns != NULL)
823 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000824 if (define->value != NULL)
825 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000826 if (define->contModel != NULL)
827 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000828 xmlFree(define);
829}
830
831/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000832 * xmlRelaxNGNewStates:
833 * @ctxt: a Relax-NG validation context
834 * @size: the default size for the container
835 *
836 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000837 *
838 * Returns the newly allocated structure or NULL in case or error
839 */
840static xmlRelaxNGStatesPtr
841xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
842{
843 xmlRelaxNGStatesPtr ret;
844
Daniel Veillard798024a2003-03-19 10:36:09 +0000845 if ((ctxt != NULL) &&
846 (ctxt->freeState != NULL) &&
847 (ctxt->freeStatesNr > 0)) {
848 ctxt->freeStatesNr--;
849 ret = ctxt->freeStates[ctxt->freeStatesNr];
850 ret->nbState = 0;
851 return(ret);
852 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000853 if (size < 16) size = 16;
854
855 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
856 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
857 if (ret == NULL) {
858 if ((ctxt != NULL) && (ctxt->error != NULL))
859 ctxt->error(ctxt->userData, "Out of memory\n");
860 return (NULL);
861 }
862 ret->nbState = 0;
863 ret->maxState = size;
864 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
865 (size) * sizeof(xmlRelaxNGValidStatePtr));
866 if (ret->tabState == NULL) {
867 if ((ctxt != NULL) && (ctxt->error != NULL))
868 ctxt->error(ctxt->userData, "Out of memory\n");
869 xmlFree(ret->tabState);
870 return (NULL);
871 }
872 return(ret);
873}
874
875/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000876 * xmlRelaxNGAddStateUniq:
877 * @ctxt: a Relax-NG validation context
878 * @states: the states container
879 * @state: the validation state
880 *
881 * Add a RelaxNG validation state to the container without checking
882 * for unicity.
883 *
884 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
885 */
886static int
887xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
888 xmlRelaxNGStatesPtr states,
889 xmlRelaxNGValidStatePtr state)
890{
891 if (state == NULL) {
892 return(-1);
893 }
894 if (states->nbState >= states->maxState) {
895 xmlRelaxNGValidStatePtr *tmp;
896 int size;
897
898 size = states->maxState * 2;
899 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
900 (size) * sizeof(xmlRelaxNGValidStatePtr));
901 if (tmp == NULL) {
902 if ((ctxt != NULL) && (ctxt->error != NULL))
903 ctxt->error(ctxt->userData, "Out of memory\n");
904 return(-1);
905 }
906 states->tabState = tmp;
907 states->maxState = size;
908 }
909 states->tabState[states->nbState++] = state;
910 return(1);
911}
912
913/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000914 * xmlRelaxNGAddState:
915 * @ctxt: a Relax-NG validation context
916 * @states: the states container
917 * @state: the validation state
918 *
919 * Add a RelaxNG validation state to the container
920 *
921 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
922 */
923static int
924xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
925 xmlRelaxNGValidStatePtr state)
926{
927 int i;
928
929 if (state == NULL) {
930 return(-1);
931 }
932 if (states->nbState >= states->maxState) {
933 xmlRelaxNGValidStatePtr *tmp;
934 int size;
935
936 size = states->maxState * 2;
937 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
938 (size) * sizeof(xmlRelaxNGValidStatePtr));
939 if (tmp == NULL) {
940 if ((ctxt != NULL) && (ctxt->error != NULL))
941 ctxt->error(ctxt->userData, "Out of memory\n");
942 return(-1);
943 }
944 states->tabState = tmp;
945 states->maxState = size;
946 }
947 for (i = 0;i < states->nbState;i++) {
948 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000949 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000950 return(0);
951 }
952 }
953 states->tabState[states->nbState++] = state;
954 return(1);
955}
956
957/**
958 * xmlRelaxNGFreeStates:
959 * @ctxt: a Relax-NG validation context
960 * @states: teh container
961 *
962 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000963 */
964static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000965xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000966 xmlRelaxNGStatesPtr states)
967{
Daniel Veillard798024a2003-03-19 10:36:09 +0000968 if (states == NULL)
969 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000970 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
971 ctxt->freeStatesMax = 40;
972 ctxt->freeStatesNr = 0;
973 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
974 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
975 if (ctxt->freeStates == NULL) {
976 if ((ctxt != NULL) && (ctxt->error != NULL))
977 ctxt->error(ctxt->userData, "Out of memory\n");
978 }
979 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
980 xmlRelaxNGStatesPtr *tmp;
981
982 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
983 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
984 if (tmp == NULL) {
985 if ((ctxt != NULL) && (ctxt->error != NULL))
986 ctxt->error(ctxt->userData, "Out of memory\n");
987 xmlFree(states->tabState);
988 xmlFree(states);
989 return;
990 }
991 ctxt->freeStates = tmp;
992 ctxt->freeStatesMax *= 2;
993 }
994 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000995 xmlFree(states->tabState);
996 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000997 } else {
998 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000999 }
1000}
1001
1002/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001003 * xmlRelaxNGNewValidState:
1004 * @ctxt: a Relax-NG validation context
1005 * @node: the current node or NULL for the document
1006 *
1007 * Allocate a new RelaxNG validation state
1008 *
1009 * Returns the newly allocated structure or NULL in case or error
1010 */
1011static xmlRelaxNGValidStatePtr
1012xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1013{
1014 xmlRelaxNGValidStatePtr ret;
1015 xmlAttrPtr attr;
1016 xmlAttrPtr attrs[MAX_ATTR];
1017 int nbAttrs = 0;
1018 xmlNodePtr root = NULL;
1019
1020 if (node == NULL) {
1021 root = xmlDocGetRootElement(ctxt->doc);
1022 if (root == NULL)
1023 return(NULL);
1024 } else {
1025 attr = node->properties;
1026 while (attr != NULL) {
1027 if (nbAttrs < MAX_ATTR)
1028 attrs[nbAttrs++] = attr;
1029 else
1030 nbAttrs++;
1031 attr = attr->next;
1032 }
1033 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001034 if ((ctxt->freeState != NULL) &&
1035 (ctxt->freeState->nbState > 0)) {
1036 ctxt->freeState->nbState--;
1037 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1038 } else {
1039 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1040 if (ret == NULL) {
1041 if ((ctxt != NULL) && (ctxt->error != NULL))
1042 ctxt->error(ctxt->userData, "Out of memory\n");
1043 return (NULL);
1044 }
1045 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001046 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001047 ret->value = NULL;
1048 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001049 if (node == NULL) {
1050 ret->node = (xmlNodePtr) ctxt->doc;
1051 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001052 } else {
1053 ret->node = node;
1054 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001055 }
1056 ret->nbAttrs = 0;
1057 if (nbAttrs > 0) {
1058 if (ret->attrs == NULL) {
1059 if (nbAttrs < 4) ret->maxAttrs = 4;
1060 else ret->maxAttrs = nbAttrs;
1061 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1062 sizeof(xmlAttrPtr));
1063 if (ret->attrs == NULL) {
1064 if ((ctxt != NULL) && (ctxt->error != NULL))
1065 ctxt->error(ctxt->userData, "Out of memory\n");
1066 return (ret);
1067 }
1068 } else if (ret->maxAttrs < nbAttrs) {
1069 xmlAttrPtr *tmp;
1070
1071 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1072 sizeof(xmlAttrPtr));
1073 if (tmp == NULL) {
1074 if ((ctxt != NULL) && (ctxt->error != NULL))
1075 ctxt->error(ctxt->userData, "Out of memory\n");
1076 return (ret);
1077 }
1078 ret->attrs = tmp;
Daniel Veillard73827cb2003-08-25 10:57:27 +00001079 ret->maxAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001080 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001081 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001082 if (nbAttrs < MAX_ATTR) {
1083 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1084 } else {
1085 attr = node->properties;
1086 nbAttrs = 0;
1087 while (attr != NULL) {
1088 ret->attrs[nbAttrs++] = attr;
1089 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001090 }
1091 }
1092 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001093 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001094 return (ret);
1095}
1096
1097/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001098 * xmlRelaxNGCopyValidState:
1099 * @ctxt: a Relax-NG validation context
1100 * @state: a validation state
1101 *
1102 * Copy the validation state
1103 *
1104 * Returns the newly allocated structure or NULL in case or error
1105 */
1106static xmlRelaxNGValidStatePtr
1107xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1108 xmlRelaxNGValidStatePtr state)
1109{
1110 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001111 unsigned int maxAttrs;
1112 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001113
1114 if (state == NULL)
1115 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001116 if ((ctxt->freeState != NULL) &&
1117 (ctxt->freeState->nbState > 0)) {
1118 ctxt->freeState->nbState--;
1119 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1120 } else {
1121 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1122 if (ret == NULL) {
1123 if ((ctxt != NULL) && (ctxt->error != NULL))
1124 ctxt->error(ctxt->userData, "Out of memory\n");
1125 return (NULL);
1126 }
1127 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001128 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001129 attrs = ret->attrs;
1130 maxAttrs = ret->maxAttrs;
1131 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1132 ret->attrs = attrs;
1133 ret->maxAttrs = maxAttrs;
1134 if (state->nbAttrs > 0) {
1135 if (ret->attrs == NULL) {
1136 ret->maxAttrs = state->maxAttrs;
1137 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1138 sizeof(xmlAttrPtr));
1139 if (ret->attrs == NULL) {
1140 if ((ctxt != NULL) && (ctxt->error != NULL))
1141 ctxt->error(ctxt->userData, "Out of memory\n");
1142 ret->nbAttrs = 0;
1143 return (ret);
1144 }
1145 } else if (ret->maxAttrs < state->nbAttrs) {
1146 xmlAttrPtr *tmp;
1147
1148 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1149 sizeof(xmlAttrPtr));
1150 if (tmp == NULL) {
1151 if ((ctxt != NULL) && (ctxt->error != NULL))
1152 ctxt->error(ctxt->userData, "Out of memory\n");
1153 ret->nbAttrs = 0;
1154 return (ret);
1155 }
1156 ret->maxAttrs = state->maxAttrs;
Daniel Veillard73827cb2003-08-25 10:57:27 +00001157 ret->attrs = tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001158 }
1159 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1160 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001161 return(ret);
1162}
1163
1164/**
1165 * xmlRelaxNGEqualValidState:
1166 * @ctxt: a Relax-NG validation context
1167 * @state1: a validation state
1168 * @state2: a validation state
1169 *
1170 * Compare the validation states for equality
1171 *
1172 * Returns 1 if equald, 0 otherwise
1173 */
1174static int
1175xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1176 xmlRelaxNGValidStatePtr state1,
1177 xmlRelaxNGValidStatePtr state2)
1178{
1179 int i;
1180
1181 if ((state1 == NULL) || (state2 == NULL))
1182 return(0);
1183 if (state1 == state2)
1184 return(1);
1185 if (state1->node != state2->node)
1186 return(0);
1187 if (state1->seq != state2->seq)
1188 return(0);
1189 if (state1->nbAttrLeft != state2->nbAttrLeft)
1190 return(0);
1191 if (state1->nbAttrs != state2->nbAttrs)
1192 return(0);
1193 if (state1->endvalue != state2->endvalue)
1194 return(0);
1195 if ((state1->value != state2->value) &&
1196 (!xmlStrEqual(state1->value, state2->value)))
1197 return(0);
1198 for (i = 0;i < state1->nbAttrs;i++) {
1199 if (state1->attrs[i] != state2->attrs[i])
1200 return(0);
1201 }
1202 return(1);
1203}
1204
1205/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001206 * xmlRelaxNGFreeValidState:
1207 * @state: a validation state structure
1208 *
1209 * Deallocate a RelaxNG validation state structure.
1210 */
1211static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001212xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1213 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001214{
1215 if (state == NULL)
1216 return;
1217
Daniel Veillard798024a2003-03-19 10:36:09 +00001218 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1219 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1220 }
1221 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1222 if (state->attrs != NULL)
1223 xmlFree(state->attrs);
1224 xmlFree(state);
1225 } else {
1226 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1227 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001228}
1229
1230/************************************************************************
1231 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001232 * Document functions *
1233 * *
1234 ************************************************************************/
1235static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1236 xmlDocPtr doc);
1237
1238/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001239 * xmlRelaxNGIncludePush:
1240 * @ctxt: the parser context
1241 * @value: the element doc
1242 *
1243 * Pushes a new include on top of the include stack
1244 *
1245 * Returns 0 in case of error, the index in the stack otherwise
1246 */
1247static int
1248xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1249 xmlRelaxNGIncludePtr value)
1250{
1251 if (ctxt->incTab == NULL) {
1252 ctxt->incMax = 4;
1253 ctxt->incNr = 0;
1254 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1255 ctxt->incMax * sizeof(ctxt->incTab[0]));
1256 if (ctxt->incTab == NULL) {
1257 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1258 return (0);
1259 }
1260 }
1261 if (ctxt->incNr >= ctxt->incMax) {
1262 ctxt->incMax *= 2;
1263 ctxt->incTab =
1264 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1265 ctxt->incMax *
1266 sizeof(ctxt->incTab[0]));
1267 if (ctxt->incTab == NULL) {
1268 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1269 return (0);
1270 }
1271 }
1272 ctxt->incTab[ctxt->incNr] = value;
1273 ctxt->inc = value;
1274 return (ctxt->incNr++);
1275}
1276
1277/**
1278 * xmlRelaxNGIncludePop:
1279 * @ctxt: the parser context
1280 *
1281 * Pops the top include from the include stack
1282 *
1283 * Returns the include just removed
1284 */
1285static xmlRelaxNGIncludePtr
1286xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1287{
1288 xmlRelaxNGIncludePtr ret;
1289
1290 if (ctxt->incNr <= 0)
1291 return (0);
1292 ctxt->incNr--;
1293 if (ctxt->incNr > 0)
1294 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1295 else
1296 ctxt->inc = NULL;
1297 ret = ctxt->incTab[ctxt->incNr];
1298 ctxt->incTab[ctxt->incNr] = 0;
1299 return (ret);
1300}
1301
1302/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001303 * xmlRelaxNGRemoveRedefine:
1304 * @ctxt: the parser context
1305 * @URL: the normalized URL
1306 * @target: the included target
1307 * @name: the define name to eliminate
1308 *
1309 * Applies the elimination algorithm of 4.7
1310 *
1311 * Returns 0 in case of error, 1 in case of success.
1312 */
1313static int
1314xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1315 const xmlChar *URL ATTRIBUTE_UNUSED,
1316 xmlNodePtr target, const xmlChar *name) {
1317 int found = 0;
1318 xmlNodePtr tmp, tmp2;
1319 xmlChar *name2;
1320
1321#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001322 if (name == NULL)
1323 xmlGenericError(xmlGenericErrorContext,
1324 "Elimination of <include> start from %s\n", URL);
1325 else
1326 xmlGenericError(xmlGenericErrorContext,
1327 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001328#endif
1329 tmp = target;
1330 while (tmp != NULL) {
1331 tmp2 = tmp->next;
1332 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1333 found = 1;
1334 xmlUnlinkNode(tmp);
1335 xmlFreeNode(tmp);
1336 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1337 name2 = xmlGetProp(tmp, BAD_CAST "name");
1338 xmlRelaxNGNormExtSpace(name2);
1339 if (name2 != NULL) {
1340 if (xmlStrEqual(name, name2)) {
1341 found = 1;
1342 xmlUnlinkNode(tmp);
1343 xmlFreeNode(tmp);
1344 }
1345 xmlFree(name2);
1346 }
1347 } else if (IS_RELAXNG(tmp, "include")) {
1348 xmlChar *href = NULL;
1349 xmlRelaxNGDocumentPtr inc = tmp->_private;
1350
1351 if ((inc != NULL) && (inc->doc != NULL) &&
1352 (inc->doc->children != NULL)) {
1353
1354 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1355#ifdef DEBUG_INCLUDE
1356 href = xmlGetProp(tmp, BAD_CAST "href");
1357#endif
1358 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1359 inc->doc->children->children, name) == 1) {
1360 found = 1;
1361 }
1362 if (href != NULL)
1363 xmlFree(href);
1364 }
1365 }
1366 }
1367 tmp = tmp2;
1368 }
1369 return(found);
1370}
1371
1372/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001373 * xmlRelaxNGLoadInclude:
1374 * @ctxt: the parser context
1375 * @URL: the normalized URL
1376 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001377 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001378 *
1379 * First lookup if the document is already loaded into the parser context,
1380 * check against recursion. If not found the resource is loaded and
1381 * the content is preprocessed before being returned back to the caller.
1382 *
1383 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1384 */
1385static xmlRelaxNGIncludePtr
1386xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001387 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001388 xmlRelaxNGIncludePtr ret = NULL;
1389 xmlDocPtr doc;
1390 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001391 xmlNodePtr root, cur;
1392
1393#ifdef DEBUG_INCLUDE
1394 xmlGenericError(xmlGenericErrorContext,
1395 "xmlRelaxNGLoadInclude(%s)\n", URL);
1396#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001397
1398 /*
1399 * check against recursion in the stack
1400 */
1401 for (i = 0;i < ctxt->incNr;i++) {
1402 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1403 if (ctxt->error != NULL)
1404 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001405 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001406 URL);
1407 ctxt->nbErrors++;
1408 return(NULL);
1409 }
1410 }
1411
1412 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001413 * load the document
1414 */
1415 doc = xmlParseFile((const char *) URL);
1416 if (doc == NULL) {
1417 if (ctxt->error != NULL)
1418 ctxt->error(ctxt->userData,
1419 "xmlRelaxNG: could not load %s\n", URL);
1420 ctxt->nbErrors++;
1421 return (NULL);
1422 }
1423
Daniel Veillard5add8682003-03-10 13:13:58 +00001424#ifdef DEBUG_INCLUDE
1425 xmlGenericError(xmlGenericErrorContext,
1426 "Parsed %s Okay\n", URL);
1427#endif
1428
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001429 /*
1430 * Allocate the document structures and register it first.
1431 */
1432 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1433 if (ret == NULL) {
1434 if (ctxt->error != NULL)
1435 ctxt->error(ctxt->userData,
1436 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1437 ctxt->nbErrors++;
1438 xmlFreeDoc(doc);
1439 return (NULL);
1440 }
1441 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1442 ret->doc = doc;
1443 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001444 ret->next = ctxt->includes;
1445 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001446
1447 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001448 * transmit the ns if needed
1449 */
1450 if (ns != NULL) {
1451 root = xmlDocGetRootElement(doc);
1452 if (root != NULL) {
1453 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1454 xmlSetProp(root, BAD_CAST"ns", ns);
1455 }
1456 }
1457 }
1458
1459 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001460 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001461 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001462 xmlRelaxNGIncludePush(ctxt, ret);
1463
1464 /*
1465 * Some preprocessing of the document content, this include recursing
1466 * in the include stack.
1467 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001468#ifdef DEBUG_INCLUDE
1469 xmlGenericError(xmlGenericErrorContext,
1470 "cleanup of %s\n", URL);
1471#endif
1472
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001473 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1474 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001475 ctxt->inc = NULL;
1476 return(NULL);
1477 }
1478
1479 /*
1480 * Pop up the include from the stack
1481 */
1482 xmlRelaxNGIncludePop(ctxt);
1483
Daniel Veillard5add8682003-03-10 13:13:58 +00001484#ifdef DEBUG_INCLUDE
1485 xmlGenericError(xmlGenericErrorContext,
1486 "Checking of %s\n", URL);
1487#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001488 /*
1489 * Check that the top element is a grammar
1490 */
1491 root = xmlDocGetRootElement(doc);
1492 if (root == NULL) {
1493 if (ctxt->error != NULL)
1494 ctxt->error(ctxt->userData,
1495 "xmlRelaxNG: included document is empty %s\n", URL);
1496 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001497 return (NULL);
1498 }
1499 if (!IS_RELAXNG(root, "grammar")) {
1500 if (ctxt->error != NULL)
1501 ctxt->error(ctxt->userData,
1502 "xmlRelaxNG: included document %s root is not a grammar\n",
1503 URL);
1504 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001505 return (NULL);
1506 }
1507
1508 /*
1509 * Elimination of redefined rules in the include.
1510 */
1511 cur = node->children;
1512 while (cur != NULL) {
1513 if (IS_RELAXNG(cur, "start")) {
1514 int found = 0;
1515
Daniel Veillard5add8682003-03-10 13:13:58 +00001516 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001517 if (!found) {
1518 if (ctxt->error != NULL)
1519 ctxt->error(ctxt->userData,
1520 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1521 URL);
1522 ctxt->nbErrors++;
1523 }
1524 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001525 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001526
1527 name = xmlGetProp(cur, BAD_CAST "name");
1528 if (name == NULL) {
1529 if (ctxt->error != NULL)
1530 ctxt->error(ctxt->userData,
1531 "xmlRelaxNG: include %s has define without name\n",
1532 URL);
1533 ctxt->nbErrors++;
1534 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001535 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001536
Daniel Veillardd2298792003-02-14 16:54:11 +00001537 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001538 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1539 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001540 if (!found) {
1541 if (ctxt->error != NULL)
1542 ctxt->error(ctxt->userData,
1543 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1544 URL, name);
1545 ctxt->nbErrors++;
1546 }
1547 xmlFree(name);
1548 }
1549 }
1550 cur = cur->next;
1551 }
1552
1553
1554 return(ret);
1555}
1556
1557/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001558 * xmlRelaxNGValidErrorPush:
1559 * @ctxt: the validation context
1560 * @err: the error code
1561 * @arg1: the first string argument
1562 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001563 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001564 *
1565 * Pushes a new error on top of the error stack
1566 *
1567 * Returns 0 in case of error, the index in the stack otherwise
1568 */
1569static int
1570xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001571 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001572{
1573 xmlRelaxNGValidErrorPtr cur;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001574#ifdef DEBUG_ERROR
1575 xmlGenericError(xmlGenericErrorContext,
1576 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1577#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001578 if (ctxt->errTab == NULL) {
1579 ctxt->errMax = 8;
1580 ctxt->errNr = 0;
1581 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1582 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1583 if (ctxt->errTab == NULL) {
1584 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1585 return (0);
1586 }
Daniel Veillard20863822003-03-22 17:51:47 +00001587 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001588 }
1589 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001590 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001591 ctxt->errTab =
1592 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001593 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001594 if (ctxt->errTab == NULL) {
1595 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1596 return (0);
1597 }
Daniel Veillard20863822003-03-22 17:51:47 +00001598 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001599 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001600 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001601 (ctxt->err->node == ctxt->state->node) &&
1602 (ctxt->err->err == err))
1603 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001604 cur = &ctxt->errTab[ctxt->errNr];
1605 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001606 if (dup) {
1607 cur->arg1 = xmlStrdup(arg1);
1608 cur->arg2 = xmlStrdup(arg2);
1609 cur->flags = ERROR_IS_DUP;
1610 } else {
1611 cur->arg1 = arg1;
1612 cur->arg2 = arg2;
1613 cur->flags = 0;
1614 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001615 if (ctxt->state != NULL) {
1616 cur->node = ctxt->state->node;
1617 cur->seq = ctxt->state->seq;
1618 } else {
1619 cur->node = NULL;
1620 cur->seq = NULL;
1621 }
1622 ctxt->err = cur;
1623 return (ctxt->errNr++);
1624}
1625
1626/**
1627 * xmlRelaxNGValidErrorPop:
1628 * @ctxt: the validation context
1629 *
1630 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001631 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001632static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001633xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1634{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001635 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001636
Daniel Veillard580ced82003-03-21 21:22:48 +00001637 if (ctxt->errNr <= 0) {
1638 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001639 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001640 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001641 ctxt->errNr--;
1642 if (ctxt->errNr > 0)
1643 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1644 else
1645 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001646 cur = &ctxt->errTab[ctxt->errNr];
1647 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001648 if (cur->arg1 != NULL)
1649 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001650 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001651 if (cur->arg2 != NULL)
1652 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001653 cur->arg2 = NULL;
1654 cur->flags = 0;
1655 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001656}
1657
Daniel Veillard42f12e92003-03-07 18:32:59 +00001658/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001659 * xmlRelaxNGDocumentPush:
1660 * @ctxt: the parser context
1661 * @value: the element doc
1662 *
1663 * Pushes a new doc on top of the doc stack
1664 *
1665 * Returns 0 in case of error, the index in the stack otherwise
1666 */
1667static int
1668xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1669 xmlRelaxNGDocumentPtr value)
1670{
1671 if (ctxt->docTab == NULL) {
1672 ctxt->docMax = 4;
1673 ctxt->docNr = 0;
1674 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1675 ctxt->docMax * sizeof(ctxt->docTab[0]));
1676 if (ctxt->docTab == NULL) {
1677 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1678 return (0);
1679 }
1680 }
1681 if (ctxt->docNr >= ctxt->docMax) {
1682 ctxt->docMax *= 2;
1683 ctxt->docTab =
1684 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1685 ctxt->docMax *
1686 sizeof(ctxt->docTab[0]));
1687 if (ctxt->docTab == NULL) {
1688 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1689 return (0);
1690 }
1691 }
1692 ctxt->docTab[ctxt->docNr] = value;
1693 ctxt->doc = value;
1694 return (ctxt->docNr++);
1695}
1696
1697/**
1698 * xmlRelaxNGDocumentPop:
1699 * @ctxt: the parser context
1700 *
1701 * Pops the top doc from the doc stack
1702 *
1703 * Returns the doc just removed
1704 */
1705static xmlRelaxNGDocumentPtr
1706xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1707{
1708 xmlRelaxNGDocumentPtr ret;
1709
1710 if (ctxt->docNr <= 0)
1711 return (0);
1712 ctxt->docNr--;
1713 if (ctxt->docNr > 0)
1714 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1715 else
1716 ctxt->doc = NULL;
1717 ret = ctxt->docTab[ctxt->docNr];
1718 ctxt->docTab[ctxt->docNr] = 0;
1719 return (ret);
1720}
1721
1722/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001723 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001724 * @ctxt: the parser context
1725 * @URL: the normalized URL
1726 * @ns: the inherited ns if any
1727 *
1728 * First lookup if the document is already loaded into the parser context,
1729 * check against recursion. If not found the resource is loaded and
1730 * the content is preprocessed before being returned back to the caller.
1731 *
1732 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1733 */
1734static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001735xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001736 const xmlChar *ns) {
1737 xmlRelaxNGDocumentPtr ret = NULL;
1738 xmlDocPtr doc;
1739 xmlNodePtr root;
1740 int i;
1741
1742 /*
1743 * check against recursion in the stack
1744 */
1745 for (i = 0;i < ctxt->docNr;i++) {
1746 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1747 if (ctxt->error != NULL)
1748 ctxt->error(ctxt->userData,
1749 "Detected an externalRef recursion for %s\n",
1750 URL);
1751 ctxt->nbErrors++;
1752 return(NULL);
1753 }
1754 }
1755
1756 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001757 * load the document
1758 */
1759 doc = xmlParseFile((const char *) URL);
1760 if (doc == NULL) {
1761 if (ctxt->error != NULL)
1762 ctxt->error(ctxt->userData,
1763 "xmlRelaxNG: could not load %s\n", URL);
1764 ctxt->nbErrors++;
1765 return (NULL);
1766 }
1767
1768 /*
1769 * Allocate the document structures and register it first.
1770 */
1771 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1772 if (ret == NULL) {
1773 if (ctxt->error != NULL)
1774 ctxt->error(ctxt->userData,
1775 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1776 ctxt->nbErrors++;
1777 xmlFreeDoc(doc);
1778 return (NULL);
1779 }
1780 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1781 ret->doc = doc;
1782 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001783 ret->next = ctxt->documents;
1784 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001785
1786 /*
1787 * transmit the ns if needed
1788 */
1789 if (ns != NULL) {
1790 root = xmlDocGetRootElement(doc);
1791 if (root != NULL) {
1792 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1793 xmlSetProp(root, BAD_CAST"ns", ns);
1794 }
1795 }
1796 }
1797
1798 /*
1799 * push it on the stack and register it in the hash table
1800 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001801 xmlRelaxNGDocumentPush(ctxt, ret);
1802
1803 /*
1804 * Some preprocessing of the document content
1805 */
1806 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1807 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001808 ctxt->doc = NULL;
1809 return(NULL);
1810 }
1811
1812 xmlRelaxNGDocumentPop(ctxt);
1813
1814 return(ret);
1815}
1816
1817/************************************************************************
1818 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001819 * Error functions *
1820 * *
1821 ************************************************************************/
1822
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001823#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1824#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1825#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1826#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1827#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001828
Daniel Veillard231d7912003-02-09 14:22:17 +00001829static const char *
1830xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1831 if (def == NULL)
1832 return("none");
1833 switch(def->type) {
1834 case XML_RELAXNG_EMPTY: return("empty");
1835 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1836 case XML_RELAXNG_EXCEPT: return("except");
1837 case XML_RELAXNG_TEXT: return("text");
1838 case XML_RELAXNG_ELEMENT: return("element");
1839 case XML_RELAXNG_DATATYPE: return("datatype");
1840 case XML_RELAXNG_VALUE: return("value");
1841 case XML_RELAXNG_LIST: return("list");
1842 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1843 case XML_RELAXNG_DEF: return("def");
1844 case XML_RELAXNG_REF: return("ref");
1845 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1846 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001847 case XML_RELAXNG_OPTIONAL: return("optional");
1848 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001849 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1850 case XML_RELAXNG_CHOICE: return("choice");
1851 case XML_RELAXNG_GROUP: return("group");
1852 case XML_RELAXNG_INTERLEAVE: return("interleave");
1853 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001854 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001855 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001856 }
1857 return("unknown");
1858}
Daniel Veillardd2298792003-02-14 16:54:11 +00001859
Daniel Veillard6eadf632003-01-23 18:29:16 +00001860/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001861 * xmlRelaxNGGetErrorString:
1862 * @err: the error code
1863 * @arg1: the first string argument
1864 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001865 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001866 * computes a formatted error string for the given error code and args
1867 *
1868 * Returns the error string, it must be deallocated by the caller
1869 */
1870static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001871xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1872 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001873 char msg[1000];
1874
1875 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001876 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001877 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001878 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001879
1880 msg[0] = 0;
1881 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001882 case XML_RELAXNG_OK:
1883 return(NULL);
1884 case XML_RELAXNG_ERR_MEMORY:
1885 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001886 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001887 snprintf(msg, 1000, "failed to validate type %s", arg1);
1888 break;
1889 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001890 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001891 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001892 case XML_RELAXNG_ERR_DUPID:
1893 snprintf(msg, 1000, "ID %s redefined", arg1);
1894 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001895 case XML_RELAXNG_ERR_TYPECMP:
1896 snprintf(msg, 1000, "failed to compare type %s", arg1);
1897 break;
1898 case XML_RELAXNG_ERR_NOSTATE:
1899 return(xmlCharStrdup("Internal error: no state"));
1900 case XML_RELAXNG_ERR_NODEFINE:
1901 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001902 case XML_RELAXNG_ERR_INTERNAL:
1903 snprintf(msg, 1000, "Internal error: %s", arg1);
1904 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001905 case XML_RELAXNG_ERR_LISTEXTRA:
1906 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1907 break;
1908 case XML_RELAXNG_ERR_INTERNODATA:
1909 return(xmlCharStrdup("Internal: interleave block has no data"));
1910 case XML_RELAXNG_ERR_INTERSEQ:
1911 return(xmlCharStrdup("Invalid sequence in interleave"));
1912 case XML_RELAXNG_ERR_INTEREXTRA:
1913 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1914 break;
1915 case XML_RELAXNG_ERR_ELEMNAME:
1916 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1917 break;
1918 case XML_RELAXNG_ERR_ELEMNONS:
1919 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1920 break;
1921 case XML_RELAXNG_ERR_ELEMWRONGNS:
1922 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1923 arg1, arg2);
1924 break;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00001925 case XML_RELAXNG_ERR_ELEMWRONG:
1926 snprintf(msg, 1000, "Did not expect element %s there",
1927 arg1);
1928 break;
1929 case XML_RELAXNG_ERR_TEXTWRONG:
1930 snprintf(msg, 1000, "Did not expect text in element %s content",
1931 arg1);
1932 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001933 case XML_RELAXNG_ERR_ELEMEXTRANS:
1934 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1935 break;
1936 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1937 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1938 break;
1939 case XML_RELAXNG_ERR_NOELEM:
1940 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1941 break;
1942 case XML_RELAXNG_ERR_NOTELEM:
1943 return(xmlCharStrdup("Expecting an element got text"));
1944 case XML_RELAXNG_ERR_ATTRVALID:
1945 snprintf(msg, 1000, "Element %s failed to validate attributes",
1946 arg1);
1947 break;
1948 case XML_RELAXNG_ERR_CONTENTVALID:
1949 snprintf(msg, 1000, "Element %s failed to validate content",
1950 arg1);
1951 break;
1952 case XML_RELAXNG_ERR_EXTRACONTENT:
1953 snprintf(msg, 1000, "Element %s has extra content: %s",
1954 arg1, arg2);
1955 break;
1956 case XML_RELAXNG_ERR_INVALIDATTR:
1957 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1958 arg1, arg2);
1959 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001960 case XML_RELAXNG_ERR_LACKDATA:
1961 snprintf(msg, 1000, "Datatype element %s contains no data",
1962 arg1);
1963 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001964 case XML_RELAXNG_ERR_DATAELEM:
1965 snprintf(msg, 1000, "Datatype element %s has child elements",
1966 arg1);
1967 break;
1968 case XML_RELAXNG_ERR_VALELEM:
1969 snprintf(msg, 1000, "Value element %s has child elements",
1970 arg1);
1971 break;
1972 case XML_RELAXNG_ERR_LISTELEM:
1973 snprintf(msg, 1000, "List element %s has child elements",
1974 arg1);
1975 break;
1976 case XML_RELAXNG_ERR_DATATYPE:
1977 snprintf(msg, 1000, "Error validating datatype %s",
1978 arg1);
1979 break;
1980 case XML_RELAXNG_ERR_VALUE:
1981 snprintf(msg, 1000, "Error validating value %s",
1982 arg1);
1983 break;
1984 case XML_RELAXNG_ERR_LIST:
1985 return(xmlCharStrdup("Error validating list"));
1986 case XML_RELAXNG_ERR_NOGRAMMAR:
1987 return(xmlCharStrdup("No top grammar defined"));
1988 case XML_RELAXNG_ERR_EXTRADATA:
1989 return(xmlCharStrdup("Extra data in the document"));
1990 default:
Daniel Veillardac297932003-04-17 12:55:35 +00001991 return(xmlCharStrdup("Unknown error !"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001992 }
1993 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001994 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001995 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00001996 msg[1000 - 1] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001997 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001998}
1999
2000/**
2001 * xmlRelaxNGValidErrorContext:
2002 * @ctxt: the validation context
2003 * @node: the node
2004 * @child: the node child generating the problem.
2005 *
2006 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00002007 */
2008static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00002009xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
2010 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00002011{
2012 int line = 0;
2013 const xmlChar *file = NULL;
2014 const xmlChar *name = NULL;
2015 const char *type = "error";
2016
2017 if ((ctxt == NULL) || (ctxt->error == NULL))
2018 return;
2019
2020 if (child != NULL)
2021 node = child;
2022
2023 if (node != NULL) {
2024 if ((node->type == XML_DOCUMENT_NODE) ||
2025 (node->type == XML_HTML_DOCUMENT_NODE)) {
2026 xmlDocPtr doc = (xmlDocPtr) node;
2027
2028 file = doc->URL;
2029 } else {
2030 /*
2031 * Try to find contextual informations to report
2032 */
2033 if (node->type == XML_ELEMENT_NODE) {
Daniel Veillard34ba3872003-07-15 13:34:05 +00002034 line = (long) node->content;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002035 } else if ((node->prev != NULL) &&
2036 (node->prev->type == XML_ELEMENT_NODE)) {
Daniel Veillard34ba3872003-07-15 13:34:05 +00002037 line = (long) node->prev->content;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002038 } else if ((node->parent != NULL) &&
2039 (node->parent->type == XML_ELEMENT_NODE)) {
Daniel Veillard34ba3872003-07-15 13:34:05 +00002040 line = (long) node->parent->content;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002041 }
2042 if ((node->doc != NULL) && (node->doc->URL != NULL))
2043 file = node->doc->URL;
2044 if (node->name != NULL)
2045 name = node->name;
2046 }
2047 }
2048
Daniel Veillard42f12e92003-03-07 18:32:59 +00002049 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002050
2051 if ((file != NULL) && (line != 0) && (name != NULL))
2052 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2053 type, file, line, name);
2054 else if ((file != NULL) && (name != NULL))
2055 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2056 type, file, name);
2057 else if ((file != NULL) && (line != 0))
2058 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2059 else if (file != NULL)
2060 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2061 else if (name != NULL)
2062 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2063 else
2064 ctxt->error(ctxt->userData, "%s\n", type);
2065}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002066
2067/**
2068 * xmlRelaxNGShowValidError:
2069 * @ctxt: the validation context
2070 * @err: the error number
2071 * @node: the node
2072 * @child: the node child generating the problem.
2073 * @arg1: the first argument
2074 * @arg2: the second argument
2075 *
2076 * Show a validation error.
2077 */
2078static void
2079xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2080 xmlNodePtr node, xmlNodePtr child,
2081 const xmlChar *arg1, const xmlChar *arg2)
2082{
2083 xmlChar *msg;
2084
2085 if (ctxt->error == NULL)
2086 return;
2087
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002088#ifdef DEBUG_ERROR
2089 xmlGenericError(xmlGenericErrorContext,
2090 "Show error %d\n", err);
2091#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002092 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2093 if (msg == NULL)
2094 return;
2095
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002096 if (ctxt->errNo == XML_RELAXNG_OK)
2097 ctxt->errNo = err;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002098 xmlRelaxNGValidErrorContext(ctxt, node, child);
2099 ctxt->error(ctxt->userData, "%s\n", msg);
2100 xmlFree(msg);
2101}
2102
2103/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002104 * xmlRelaxNGPopErrors:
2105 * @ctxt: the validation context
2106 * @level: the error level in the stack
2107 *
2108 * pop and discard all errors until the given level is reached
2109 */
2110static void
2111xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2112 int i;
2113 xmlRelaxNGValidErrorPtr err;
2114
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002115#ifdef DEBUG_ERROR
2116 xmlGenericError(xmlGenericErrorContext,
2117 "Pop errors till level %d\n", level);
2118#endif
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002119 for (i = level;i < ctxt->errNr;i++) {
2120 err = &ctxt->errTab[i];
2121 if (err->flags & ERROR_IS_DUP) {
2122 if (err->arg1 != NULL)
2123 xmlFree((xmlChar *)err->arg1);
2124 err->arg1 = NULL;
2125 if (err->arg2 != NULL)
2126 xmlFree((xmlChar *)err->arg2);
2127 err->arg2 = NULL;
2128 err->flags = 0;
2129 }
2130 }
2131 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002132 if (ctxt->errNr <= 0)
2133 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002134}
2135/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002136 * xmlRelaxNGDumpValidError:
2137 * @ctxt: the validation context
2138 *
2139 * Show all validation error over a given index.
2140 */
2141static void
2142xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002143 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002144 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002145
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002146#ifdef DEBUG_ERROR
2147 xmlGenericError(xmlGenericErrorContext,
2148 "Dumping error stack %d errors\n", ctxt->errNr);
2149#endif
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002150 for (i = 0, k = 0;i < ctxt->errNr;i++) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00002151 err = &ctxt->errTab[i];
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002152 if (k < MAX_ERROR) {
2153 for (j = 0;j < i;j++) {
2154 dup = &ctxt->errTab[j];
2155 if ((err->err == dup->err) && (err->node == dup->node) &&
2156 (xmlStrEqual(err->arg1, dup->arg1)) &&
2157 (xmlStrEqual(err->arg2, dup->arg2))) {
2158 goto skip;
2159 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002160 }
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002161 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2162 err->arg1, err->arg2);
2163 k++;
Daniel Veillard580ced82003-03-21 21:22:48 +00002164 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002165skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002166 if (err->flags & ERROR_IS_DUP) {
2167 if (err->arg1 != NULL)
2168 xmlFree((xmlChar *)err->arg1);
2169 err->arg1 = NULL;
2170 if (err->arg2 != NULL)
2171 xmlFree((xmlChar *)err->arg2);
2172 err->arg2 = NULL;
2173 err->flags = 0;
2174 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002175 }
2176 ctxt->errNr = 0;
2177}
2178/**
2179 * xmlRelaxNGAddValidError:
2180 * @ctxt: the validation context
2181 * @err: the error number
2182 * @arg1: the first argument
2183 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002184 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002185 *
2186 * Register a validation error, either generating it if it's sure
2187 * or stacking it for later handling if unsure.
2188 */
2189static void
2190xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002191 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002192{
2193 if ((ctxt == NULL) || (ctxt->error == NULL))
2194 return;
2195
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002196#ifdef DEBUG_ERROR
2197 xmlGenericError(xmlGenericErrorContext,
2198 "Adding error %d\n", err);
2199#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002200 /*
2201 * generate the error directly
2202 */
2203 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2204 xmlNodePtr node, seq;
2205 /*
2206 * Flush first any stacked error which might be the
2207 * real cause of the problem.
2208 */
2209 if (ctxt->errNr != 0)
2210 xmlRelaxNGDumpValidError(ctxt);
2211 if (ctxt->state != NULL) {
2212 node = ctxt->state->node;
2213 seq = ctxt->state->seq;
2214 } else {
2215 node = seq = NULL;
2216 }
2217 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2218 }
2219 /*
2220 * Stack the error for later processing if needed
2221 */
2222 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002223 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002224 }
2225}
2226
Daniel Veillard6eadf632003-01-23 18:29:16 +00002227
2228/************************************************************************
2229 * *
2230 * Type library hooks *
2231 * *
2232 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002233static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2234 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002235
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002236/**
2237 * xmlRelaxNGSchemaTypeHave:
2238 * @data: data needed for the library
2239 * @type: the type name
2240 *
2241 * Check if the given type is provided by
2242 * the W3C XMLSchema Datatype library.
2243 *
2244 * Returns 1 if yes, 0 if no and -1 in case of error.
2245 */
2246static int
2247xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002248 const xmlChar *type) {
2249 xmlSchemaTypePtr typ;
2250
2251 if (type == NULL)
2252 return(-1);
2253 typ = xmlSchemaGetPredefinedType(type,
2254 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2255 if (typ == NULL)
2256 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002257 return(1);
2258}
2259
2260/**
2261 * xmlRelaxNGSchemaTypeCheck:
2262 * @data: data needed for the library
2263 * @type: the type name
2264 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002265 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002266 *
2267 * Check if the given type and value are validated by
2268 * the W3C XMLSchema Datatype library.
2269 *
2270 * Returns 1 if yes, 0 if no and -1 in case of error.
2271 */
2272static int
2273xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002274 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002275 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002276 void **result,
2277 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002278 xmlSchemaTypePtr typ;
2279 int ret;
2280
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002281 if ((type == NULL) || (value == NULL))
2282 return(-1);
2283 typ = xmlSchemaGetPredefinedType(type,
2284 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2285 if (typ == NULL)
2286 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002287 ret = xmlSchemaValPredefTypeNode(typ, value,
2288 (xmlSchemaValPtr *) result, node);
2289 if (ret == 2) /* special ID error code */
2290 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002291 if (ret == 0)
2292 return(1);
2293 if (ret > 0)
2294 return(0);
2295 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002296}
2297
2298/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002299 * xmlRelaxNGSchemaFacetCheck:
2300 * @data: data needed for the library
2301 * @type: the type name
2302 * @facet: the facet name
2303 * @val: the facet value
2304 * @strval: the string value
2305 * @value: the value to check
2306 *
2307 * Function provided by a type library to check a value facet
2308 *
2309 * Returns 1 if yes, 0 if no and -1 in case of error.
2310 */
2311static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002312xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002313 const xmlChar *facetname, const xmlChar *val,
2314 const xmlChar *strval, void *value) {
2315 xmlSchemaFacetPtr facet;
2316 xmlSchemaTypePtr typ;
2317 int ret;
2318
2319 if ((type == NULL) || (strval == NULL))
2320 return(-1);
2321 typ = xmlSchemaGetPredefinedType(type,
2322 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2323 if (typ == NULL)
2324 return(-1);
2325
2326 facet = xmlSchemaNewFacet();
2327 if (facet == NULL)
2328 return(-1);
2329
2330 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2331 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2332 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2333 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2334 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2335 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2336 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2337 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2338 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2339 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2340 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2341 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2342 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2343 facet->type = XML_SCHEMA_FACET_PATTERN;
2344 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2345 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2346 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2347 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2348 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2349 facet->type = XML_SCHEMA_FACET_LENGTH;
2350 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2351 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2352 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2353 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2354 } else {
2355 xmlSchemaFreeFacet(facet);
2356 return(-1);
2357 }
2358 facet->value = xmlStrdup(val);
2359 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2360 if (ret != 0) {
2361 xmlSchemaFreeFacet(facet);
2362 return(-1);
2363 }
2364 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2365 xmlSchemaFreeFacet(facet);
2366 if (ret != 0)
2367 return(-1);
2368 return(0);
2369}
2370
2371/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002372 * xmlRelaxNGSchemaFreeValue:
2373 * @data: data needed for the library
2374 * @value: the value to free
2375 *
2376 * Function provided by a type library to free a Schemas value
2377 *
2378 * Returns 1 if yes, 0 if no and -1 in case of error.
2379 */
2380static void
2381xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2382 xmlSchemaFreeValue(value);
2383}
2384
2385/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002386 * xmlRelaxNGSchemaTypeCompare:
2387 * @data: data needed for the library
2388 * @type: the type name
2389 * @value1: the first value
2390 * @value2: the second value
2391 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002392 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002393 * Datatype library.
2394 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002395 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002396 */
2397static int
2398xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002399 const xmlChar *type,
2400 const xmlChar *value1,
2401 xmlNodePtr ctxt1,
2402 void *comp1,
2403 const xmlChar *value2,
2404 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002405 int ret;
2406 xmlSchemaTypePtr typ;
2407 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2408
2409 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2410 return(-1);
2411 typ = xmlSchemaGetPredefinedType(type,
2412 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2413 if (typ == NULL)
2414 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002415 if (comp1 == NULL) {
2416 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2417 if (ret != 0)
2418 return(-1);
2419 if (res1 == NULL)
2420 return(-1);
2421 } else {
2422 res1 = (xmlSchemaValPtr) comp1;
2423 }
2424 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002425 if (ret != 0) {
2426 xmlSchemaFreeValue(res1);
2427 return(-1);
2428 }
2429 if (res1 == NULL) {
2430 xmlSchemaFreeValue(res1);
2431 return(-1);
2432 }
2433 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002434 if (res1 != (xmlSchemaValPtr) comp1)
2435 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002436 xmlSchemaFreeValue(res2);
2437 if (ret == -2)
2438 return(-1);
2439 if (ret == 0)
2440 return(1);
2441 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002442}
2443
2444/**
2445 * xmlRelaxNGDefaultTypeHave:
2446 * @data: data needed for the library
2447 * @type: the type name
2448 *
2449 * Check if the given type is provided by
2450 * the default datatype library.
2451 *
2452 * Returns 1 if yes, 0 if no and -1 in case of error.
2453 */
2454static int
2455xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2456 if (type == NULL)
2457 return(-1);
2458 if (xmlStrEqual(type, BAD_CAST "string"))
2459 return(1);
2460 if (xmlStrEqual(type, BAD_CAST "token"))
2461 return(1);
2462 return(0);
2463}
2464
2465/**
2466 * xmlRelaxNGDefaultTypeCheck:
2467 * @data: data needed for the library
2468 * @type: the type name
2469 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002470 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002471 *
2472 * Check if the given type and value are validated by
2473 * the default datatype library.
2474 *
2475 * Returns 1 if yes, 0 if no and -1 in case of error.
2476 */
2477static int
2478xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2479 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002480 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002481 void **result ATTRIBUTE_UNUSED,
2482 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002483 if (value == NULL)
2484 return(-1);
2485 if (xmlStrEqual(type, BAD_CAST "string"))
2486 return(1);
2487 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002488 return(1);
2489 }
2490
2491 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002492}
2493
2494/**
2495 * xmlRelaxNGDefaultTypeCompare:
2496 * @data: data needed for the library
2497 * @type: the type name
2498 * @value1: the first value
2499 * @value2: the second value
2500 *
2501 * Compare two values accordingly a type from the default
2502 * datatype library.
2503 *
2504 * Returns 1 if yes, 0 if no and -1 in case of error.
2505 */
2506static int
2507xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002508 const xmlChar *type,
2509 const xmlChar *value1,
2510 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2511 void *comp1 ATTRIBUTE_UNUSED,
2512 const xmlChar *value2,
2513 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002514 int ret = -1;
2515
2516 if (xmlStrEqual(type, BAD_CAST "string")) {
2517 ret = xmlStrEqual(value1, value2);
2518 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2519 if (!xmlStrEqual(value1, value2)) {
2520 xmlChar *nval, *nvalue;
2521
2522 /*
2523 * TODO: trivial optimizations are possible by
2524 * computing at compile-time
2525 */
2526 nval = xmlRelaxNGNormalize(NULL, value1);
2527 nvalue = xmlRelaxNGNormalize(NULL, value2);
2528
Daniel Veillardd4310742003-02-18 21:12:46 +00002529 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002530 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002531 else if (xmlStrEqual(nval, nvalue))
2532 ret = 1;
2533 else
2534 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002535 if (nval != NULL)
2536 xmlFree(nval);
2537 if (nvalue != NULL)
2538 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002539 } else
2540 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002541 }
2542 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002543}
2544
2545static int xmlRelaxNGTypeInitialized = 0;
2546static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2547
2548/**
2549 * xmlRelaxNGFreeTypeLibrary:
2550 * @lib: the type library structure
2551 * @namespace: the URI bound to the library
2552 *
2553 * Free the structure associated to the type library
2554 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002555static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002556xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2557 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2558 if (lib == NULL)
2559 return;
2560 if (lib->namespace != NULL)
2561 xmlFree((xmlChar *)lib->namespace);
2562 xmlFree(lib);
2563}
2564
2565/**
2566 * xmlRelaxNGRegisterTypeLibrary:
2567 * @namespace: the URI bound to the library
2568 * @data: data associated to the library
2569 * @have: the provide function
2570 * @check: the checking function
2571 * @comp: the comparison function
2572 *
2573 * Register a new type library
2574 *
2575 * Returns 0 in case of success and -1 in case of error.
2576 */
2577static int
2578xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2579 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002580 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2581 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002582 xmlRelaxNGTypeLibraryPtr lib;
2583 int ret;
2584
2585 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2586 (check == NULL) || (comp == NULL))
2587 return(-1);
2588 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2589 xmlGenericError(xmlGenericErrorContext,
2590 "Relax-NG types library '%s' already registered\n",
2591 namespace);
2592 return(-1);
2593 }
2594 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2595 if (lib == NULL) {
2596 xmlGenericError(xmlGenericErrorContext,
2597 "Relax-NG types library '%s' malloc() failed\n",
2598 namespace);
2599 return (-1);
2600 }
2601 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2602 lib->namespace = xmlStrdup(namespace);
2603 lib->data = data;
2604 lib->have = have;
2605 lib->comp = comp;
2606 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002607 lib->facet = facet;
2608 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002609 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2610 if (ret < 0) {
2611 xmlGenericError(xmlGenericErrorContext,
2612 "Relax-NG types library failed to register '%s'\n",
2613 namespace);
2614 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2615 return(-1);
2616 }
2617 return(0);
2618}
2619
2620/**
2621 * xmlRelaxNGInitTypes:
2622 *
2623 * Initilize the default type libraries.
2624 *
2625 * Returns 0 in case of success and -1 in case of error.
2626 */
2627static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002628xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002629 if (xmlRelaxNGTypeInitialized != 0)
2630 return(0);
2631 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2632 if (xmlRelaxNGRegisteredTypes == NULL) {
2633 xmlGenericError(xmlGenericErrorContext,
2634 "Failed to allocate sh table for Relax-NG types\n");
2635 return(-1);
2636 }
2637 xmlRelaxNGRegisterTypeLibrary(
2638 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2639 NULL,
2640 xmlRelaxNGSchemaTypeHave,
2641 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002642 xmlRelaxNGSchemaTypeCompare,
2643 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002644 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002645 xmlRelaxNGRegisterTypeLibrary(
2646 xmlRelaxNGNs,
2647 NULL,
2648 xmlRelaxNGDefaultTypeHave,
2649 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002650 xmlRelaxNGDefaultTypeCompare,
2651 NULL,
2652 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002653 xmlRelaxNGTypeInitialized = 1;
2654 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002655}
2656
2657/**
2658 * xmlRelaxNGCleanupTypes:
2659 *
2660 * Cleanup the default Schemas type library associated to RelaxNG
2661 */
2662void
2663xmlRelaxNGCleanupTypes(void) {
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002664 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002665 if (xmlRelaxNGTypeInitialized == 0)
2666 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002667 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2668 xmlRelaxNGFreeTypeLibrary);
2669 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002670}
2671
2672/************************************************************************
2673 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002674 * Compiling element content into regexp *
2675 * *
2676 * Sometime the element content can be compiled into a pure regexp, *
2677 * This allows a faster execution and streamability at that level *
2678 * *
2679 ************************************************************************/
2680
Daniel Veillard52b48c72003-04-13 19:53:42 +00002681static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2682 xmlRelaxNGDefinePtr def);
2683
Daniel Veillard952379b2003-03-17 15:37:12 +00002684/**
2685 * xmlRelaxNGIsCompileable:
2686 * @define: the definition to check
2687 *
2688 * Check if a definition is nullable.
2689 *
2690 * Returns 1 if yes, 0 if no and -1 in case of error
2691 */
2692static int
2693xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00002694 int ret = -1;
2695
Daniel Veillard952379b2003-03-17 15:37:12 +00002696 if (def == NULL) {
2697 return(-1);
2698 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002699 if ((def->type != XML_RELAXNG_ELEMENT) &&
2700 (def->dflags & IS_COMPILABLE))
2701 return(1);
2702 if ((def->type != XML_RELAXNG_ELEMENT) &&
2703 (def->dflags & IS_NOT_COMPILABLE))
2704 return(0);
Daniel Veillard952379b2003-03-17 15:37:12 +00002705 switch(def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002706 case XML_RELAXNG_NOOP:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002707 ret = xmlRelaxNGIsCompileable(def->content);
2708 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002709 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002710 case XML_RELAXNG_EMPTY:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002711 ret = 1;
2712 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002713 case XML_RELAXNG_ELEMENT:
Daniel Veillardd94849b2003-07-28 13:02:24 +00002714 /*
2715 * Check if the element content is compileable
2716 */
Daniel Veillard52b48c72003-04-13 19:53:42 +00002717 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2718 ((def->dflags & IS_COMPILABLE) == 0)) {
Daniel Veillard2134ab12003-07-23 19:56:29 +00002719 xmlRelaxNGDefinePtr list;
2720 list = def->content;
2721 while (list != NULL) {
2722 ret = xmlRelaxNGIsCompileable(list);
2723 if (ret != 1)
2724 break;
2725 list = list->next;
2726 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002727 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2728 if (ret == 1) def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002729#ifdef DEBUG_COMPILE
2730 if (ret == 1) {
2731 xmlGenericError(xmlGenericErrorContext,
2732 "element content for %s is compilable\n",
2733 def->name);
2734 } else if (ret == 0) {
2735 xmlGenericError(xmlGenericErrorContext,
2736 "element content for %s is not compilable\n",
2737 def->name);
2738 } else {
2739 xmlGenericError(xmlGenericErrorContext,
2740 "Problem in RelaxNGIsCompileable for element %s\n",
2741 def->name);
2742 }
2743#endif
Daniel Veillard52b48c72003-04-13 19:53:42 +00002744 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002745 /*
2746 * All elements return a compileable status unless they
2747 * are generic like anyName
2748 */
2749 if ((def->nameClass != NULL) || (def->name == NULL))
2750 ret = 0;
2751 else
2752 ret = 1;
2753 return(ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002754 case XML_RELAXNG_REF:
2755 case XML_RELAXNG_EXTERNALREF:
2756 case XML_RELAXNG_PARENTREF:
2757 if (def->depth == -20) {
2758 return(1);
2759 } else {
2760 xmlRelaxNGDefinePtr list;
2761
2762 def->depth = -20;
2763 list = def->content;
2764 while (list != NULL) {
2765 ret = xmlRelaxNGIsCompileable(list);
2766 if (ret != 1)
2767 break;
2768 list = list->next;
2769 }
2770 }
2771 break;
2772 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002773 case XML_RELAXNG_OPTIONAL:
2774 case XML_RELAXNG_ZEROORMORE:
2775 case XML_RELAXNG_ONEORMORE:
2776 case XML_RELAXNG_CHOICE:
2777 case XML_RELAXNG_GROUP:
2778 case XML_RELAXNG_DEF: {
2779 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002780
2781 list = def->content;
2782 while (list != NULL) {
2783 ret = xmlRelaxNGIsCompileable(list);
2784 if (ret != 1)
Daniel Veillard52b48c72003-04-13 19:53:42 +00002785 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002786 list = list->next;
2787 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002788 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002789 }
2790 case XML_RELAXNG_EXCEPT:
2791 case XML_RELAXNG_ATTRIBUTE:
2792 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002793 case XML_RELAXNG_DATATYPE:
2794 case XML_RELAXNG_LIST:
2795 case XML_RELAXNG_PARAM:
2796 case XML_RELAXNG_VALUE:
2797 ret = 0;
2798 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002799 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002800 ret = -1;
2801 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002802 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002803 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2804 if (ret == 1) def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002805#ifdef DEBUG_COMPILE
2806 if (ret == 1) {
2807 xmlGenericError(xmlGenericErrorContext,
2808 "RelaxNGIsCompileable %s : true\n",
2809 xmlRelaxNGDefName(def));
2810 } else if (ret == 0) {
2811 xmlGenericError(xmlGenericErrorContext,
2812 "RelaxNGIsCompileable %s : false\n",
2813 xmlRelaxNGDefName(def));
2814 } else {
2815 xmlGenericError(xmlGenericErrorContext,
2816 "Problem in RelaxNGIsCompileable %s\n",
2817 xmlRelaxNGDefName(def));
2818 }
2819#endif
Daniel Veillard52b48c72003-04-13 19:53:42 +00002820 return(ret);
2821}
2822
2823/**
2824 * xmlRelaxNGCompile:
2825 * ctxt: the RelaxNG parser context
2826 * @define: the definition tree to compile
2827 *
2828 * Compile the set of definitions, it works recursively, till the
2829 * element boundaries, where it tries to compile the content if possible
2830 *
2831 * Returns 0 if success and -1 in case of error
2832 */
2833static int
2834xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2835 int ret = 0;
2836 xmlRelaxNGDefinePtr list;
2837
2838 if ((ctxt == NULL) || (def == NULL)) return(-1);
2839
2840 switch(def->type) {
2841 case XML_RELAXNG_START:
2842 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
2843 xmlAutomataPtr oldam = ctxt->am;
2844 xmlAutomataStatePtr oldstate = ctxt->state;
2845
2846 def->depth = -25;
2847
2848 list = def->content;
2849 ctxt->am = xmlNewAutomata();
2850 if (ctxt->am == NULL)
2851 return(-1);
2852 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2853 while (list != NULL) {
2854 xmlRelaxNGCompile(ctxt, list);
2855 list = list->next;
2856 }
2857 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2858 def->contModel = xmlAutomataCompile(ctxt->am);
2859 xmlRegexpIsDeterminist(def->contModel);
2860
2861 xmlFreeAutomata(ctxt->am);
2862 ctxt->state = oldstate;
2863 ctxt->am = oldam;
2864 }
2865 break;
2866 case XML_RELAXNG_ELEMENT:
2867 if ((ctxt->am != NULL) && (def->name != NULL)) {
2868 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002869 ctxt->state, NULL, def->name, def->ns, def);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002870 }
2871 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2872 xmlAutomataPtr oldam = ctxt->am;
2873 xmlAutomataStatePtr oldstate = ctxt->state;
2874
2875 def->depth = -25;
2876
2877 list = def->content;
2878 ctxt->am = xmlNewAutomata();
2879 if (ctxt->am == NULL)
2880 return(-1);
2881 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2882 while (list != NULL) {
2883 xmlRelaxNGCompile(ctxt, list);
2884 list = list->next;
2885 }
2886 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2887 def->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002888 if (!xmlRegexpIsDeterminist(def->contModel)) {
2889 /*
2890 * we can only use the automata if it is determinist
2891 */
2892 xmlRegFreeRegexp(def->contModel);
2893 def->contModel = NULL;
2894 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002895 xmlFreeAutomata(ctxt->am);
2896 ctxt->state = oldstate;
2897 ctxt->am = oldam;
2898 } else {
2899 xmlAutomataPtr oldam = ctxt->am;
2900
2901 /*
2902 * we can't build the content model for this element content
2903 * but it still might be possible to build it for some of its
2904 * children, recurse.
2905 */
2906 ret = xmlRelaxNGTryCompile(ctxt, def);
2907 ctxt->am = oldam;
2908 }
2909 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002910 case XML_RELAXNG_NOOP:
2911 ret = xmlRelaxNGCompile(ctxt, def->content);
2912 break;
2913 case XML_RELAXNG_OPTIONAL: {
2914 xmlAutomataStatePtr oldstate = ctxt->state;
2915
2916 xmlRelaxNGCompile(ctxt, def->content);
2917 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2918 break;
2919 }
2920 case XML_RELAXNG_ZEROORMORE: {
2921 xmlAutomataStatePtr oldstate;
2922
2923 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2924 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002925 list = def->content;
2926 while (list != NULL) {
2927 xmlRelaxNGCompile(ctxt, list);
2928 list = list->next;
2929 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002930 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2931 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2932 break;
2933 }
2934 case XML_RELAXNG_ONEORMORE: {
2935 xmlAutomataStatePtr oldstate;
2936
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002937 list = def->content;
2938 while (list != NULL) {
2939 xmlRelaxNGCompile(ctxt, list);
2940 list = list->next;
2941 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002942 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002943 list = def->content;
2944 while (list != NULL) {
2945 xmlRelaxNGCompile(ctxt, list);
2946 list = list->next;
2947 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002948 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2949 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2950 break;
2951 }
2952 case XML_RELAXNG_CHOICE: {
2953 xmlAutomataStatePtr target = NULL;
2954 xmlAutomataStatePtr oldstate = ctxt->state;
2955
2956 list = def->content;
2957 while (list != NULL) {
2958 ctxt->state = oldstate;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002959 ret = xmlRelaxNGCompile(ctxt, list);
2960 if (ret != 0)
2961 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002962 if (target == NULL)
2963 target = ctxt->state;
2964 else {
2965 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, target);
2966 }
2967 list = list->next;
2968 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002969 ctxt->state = target;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002970
2971 break;
2972 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00002973 case XML_RELAXNG_REF:
2974 case XML_RELAXNG_EXTERNALREF:
2975 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002976 case XML_RELAXNG_GROUP:
2977 case XML_RELAXNG_DEF:
2978 list = def->content;
2979 while (list != NULL) {
Daniel Veillard2134ab12003-07-23 19:56:29 +00002980 ret = xmlRelaxNGCompile(ctxt, list);
2981 if (ret != 0)
2982 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002983 list = list->next;
2984 }
2985 break;
2986 case XML_RELAXNG_TEXT: {
2987 xmlAutomataStatePtr oldstate;
2988
2989 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2990 oldstate = ctxt->state;
2991 xmlRelaxNGCompile(ctxt, def->content);
2992 xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state,
2993 BAD_CAST "#text", NULL);
2994 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2995 break;
2996 }
2997 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002998 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002999 break;
3000 case XML_RELAXNG_EXCEPT:
3001 case XML_RELAXNG_ATTRIBUTE:
3002 case XML_RELAXNG_INTERLEAVE:
3003 case XML_RELAXNG_NOT_ALLOWED:
3004 case XML_RELAXNG_DATATYPE:
3005 case XML_RELAXNG_LIST:
3006 case XML_RELAXNG_PARAM:
3007 case XML_RELAXNG_VALUE:
Daniel Veillardac297932003-04-17 12:55:35 +00003008 /* This should not happen and generate an internal error */
3009 fprintf(stderr, "RNG internal error trying to compile %s\n",
3010 xmlRelaxNGDefName(def));
Daniel Veillard52b48c72003-04-13 19:53:42 +00003011 break;
3012 }
3013 return(ret);
3014}
3015
3016/**
3017 * xmlRelaxNGTryCompile:
3018 * ctxt: the RelaxNG parser context
3019 * @define: the definition tree to compile
3020 *
3021 * Try to compile the set of definitions, it works recursively,
3022 * possibly ignoring parts which cannot be compiled.
3023 *
3024 * Returns 0 if success and -1 in case of error
3025 */
3026static int
3027xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
3028 int ret = 0;
3029 xmlRelaxNGDefinePtr list;
3030
3031 if ((ctxt == NULL) || (def == NULL)) return(-1);
3032
3033 if ((def->type == XML_RELAXNG_START) ||
3034 (def->type == XML_RELAXNG_ELEMENT)) {
3035 ret = xmlRelaxNGIsCompileable(def);
3036 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3037 ctxt->am = NULL;
3038 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003039#ifdef DEBUG_PROGRESSIVE
3040 if (ret == 0) {
3041 if (def->type == XML_RELAXNG_START)
3042 xmlGenericError(xmlGenericErrorContext,
3043 "compiled the start\n");
3044 else
3045 xmlGenericError(xmlGenericErrorContext,
3046 "compiled element %s\n", def->name);
3047 } else {
3048 if (def->type == XML_RELAXNG_START)
3049 xmlGenericError(xmlGenericErrorContext,
3050 "failed to compile the start\n");
3051 else
3052 xmlGenericError(xmlGenericErrorContext,
3053 "failed to compile element %s\n", def->name);
3054 }
3055#endif
Daniel Veillard52b48c72003-04-13 19:53:42 +00003056 return(ret);
3057 }
3058 }
3059 switch(def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003060 case XML_RELAXNG_NOOP:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003061 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3062 break;
3063 case XML_RELAXNG_TEXT:
3064 case XML_RELAXNG_DATATYPE:
3065 case XML_RELAXNG_LIST:
3066 case XML_RELAXNG_PARAM:
3067 case XML_RELAXNG_VALUE:
3068 case XML_RELAXNG_EMPTY:
3069 case XML_RELAXNG_ELEMENT:
3070 ret = 0;
3071 break;
3072 case XML_RELAXNG_OPTIONAL:
3073 case XML_RELAXNG_ZEROORMORE:
3074 case XML_RELAXNG_ONEORMORE:
3075 case XML_RELAXNG_CHOICE:
3076 case XML_RELAXNG_GROUP:
3077 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003078 case XML_RELAXNG_START:
3079 case XML_RELAXNG_REF:
3080 case XML_RELAXNG_EXTERNALREF:
3081 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003082 list = def->content;
3083 while (list != NULL) {
3084 ret = xmlRelaxNGTryCompile(ctxt, list);
3085 if (ret != 0)
3086 break;
3087 list = list->next;
3088 }
3089 break;
3090 case XML_RELAXNG_EXCEPT:
3091 case XML_RELAXNG_ATTRIBUTE:
3092 case XML_RELAXNG_INTERLEAVE:
3093 case XML_RELAXNG_NOT_ALLOWED:
3094 ret = 0;
3095 break;
3096 }
3097 return(ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003098}
3099
3100/************************************************************************
3101 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003102 * Parsing functions *
3103 * *
3104 ************************************************************************/
3105
3106static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
3107 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3108static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
3109 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3110static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00003111 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003112static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
3113 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003114static xmlRelaxNGPtr xmlRelaxNGParseDocument(
3115 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003116static int xmlRelaxNGParseGrammarContent(
3117 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003118static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
3119 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3120 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00003121static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
3122 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003123static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3124 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003125
3126
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003127#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003128
3129/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003130 * xmlRelaxNGIsNullable:
3131 * @define: the definition to verify
3132 *
3133 * Check if a definition is nullable.
3134 *
3135 * Returns 1 if yes, 0 if no and -1 in case of error
3136 */
3137static int
3138xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
3139 int ret;
3140 if (define == NULL)
3141 return(-1);
3142
Daniel Veillarde063f482003-03-21 16:53:17 +00003143 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003144 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003145 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003146 return(0);
3147 switch (define->type) {
3148 case XML_RELAXNG_EMPTY:
3149 case XML_RELAXNG_TEXT:
3150 ret = 1; break;
3151 case XML_RELAXNG_NOOP:
3152 case XML_RELAXNG_DEF:
3153 case XML_RELAXNG_REF:
3154 case XML_RELAXNG_EXTERNALREF:
3155 case XML_RELAXNG_PARENTREF:
3156 case XML_RELAXNG_ONEORMORE:
3157 ret = xmlRelaxNGIsNullable(define->content);
3158 break;
3159 case XML_RELAXNG_EXCEPT:
3160 case XML_RELAXNG_NOT_ALLOWED:
3161 case XML_RELAXNG_ELEMENT:
3162 case XML_RELAXNG_DATATYPE:
3163 case XML_RELAXNG_PARAM:
3164 case XML_RELAXNG_VALUE:
3165 case XML_RELAXNG_LIST:
3166 case XML_RELAXNG_ATTRIBUTE:
3167 ret = 0; break;
3168 case XML_RELAXNG_CHOICE: {
3169 xmlRelaxNGDefinePtr list = define->content;
3170
3171 while (list != NULL) {
3172 ret = xmlRelaxNGIsNullable(list);
3173 if (ret != 0)
3174 goto done;
3175 list = list->next;
3176 }
3177 ret = 0; break;
3178 }
3179 case XML_RELAXNG_START:
3180 case XML_RELAXNG_INTERLEAVE:
3181 case XML_RELAXNG_GROUP: {
3182 xmlRelaxNGDefinePtr list = define->content;
3183
3184 while (list != NULL) {
3185 ret = xmlRelaxNGIsNullable(list);
3186 if (ret != 1)
3187 goto done;
3188 list = list->next;
3189 }
3190 return(1);
3191 }
3192 default:
3193 return(-1);
3194 }
3195done:
3196 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003197 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003198 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00003199 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003200 return(ret);
3201}
3202
3203/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003204 * xmlRelaxNGIsBlank:
3205 * @str: a string
3206 *
3207 * Check if a string is ignorable c.f. 4.2. Whitespace
3208 *
3209 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3210 */
3211static int
3212xmlRelaxNGIsBlank(xmlChar *str) {
3213 if (str == NULL)
3214 return(1);
3215 while (*str != 0) {
3216 if (!(IS_BLANK(*str))) return(0);
3217 str++;
3218 }
3219 return(1);
3220}
3221
Daniel Veillard6eadf632003-01-23 18:29:16 +00003222/**
3223 * xmlRelaxNGGetDataTypeLibrary:
3224 * @ctxt: a Relax-NG parser context
3225 * @node: the current data or value element
3226 *
3227 * Applies algorithm from 4.3. datatypeLibrary attribute
3228 *
3229 * Returns the datatypeLibary value or NULL if not found
3230 */
3231static xmlChar *
3232xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3233 xmlNodePtr node) {
3234 xmlChar *ret, *escape;
3235
Daniel Veillard6eadf632003-01-23 18:29:16 +00003236 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3237 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3238 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003239 if (ret[0] == 0) {
3240 xmlFree(ret);
3241 return(NULL);
3242 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003243 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00003244 if (escape == NULL) {
3245 return(ret);
3246 }
3247 xmlFree(ret);
3248 return(escape);
3249 }
3250 }
3251 node = node->parent;
3252 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003253 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3254 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003255 if (ret[0] == 0) {
3256 xmlFree(ret);
3257 return(NULL);
3258 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003259 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3260 if (escape == NULL) {
3261 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003262 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003263 xmlFree(ret);
3264 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003265 }
3266 node = node->parent;
3267 }
3268 return(NULL);
3269}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003270
3271/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003272 * xmlRelaxNGParseValue:
3273 * @ctxt: a Relax-NG parser context
3274 * @node: the data node.
3275 *
3276 * parse the content of a RelaxNG value node.
3277 *
3278 * Returns the definition pointer or NULL in case of error
3279 */
3280static xmlRelaxNGDefinePtr
3281xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3282 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003283 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003284 xmlChar *type;
3285 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003286 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003287
Daniel Veillardfd573f12003-03-16 17:52:32 +00003288 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003289 if (def == NULL)
3290 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003291 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003292
3293 type = xmlGetProp(node, BAD_CAST "type");
3294 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003295 xmlRelaxNGNormExtSpace(type);
3296 if (xmlValidateNCName(type, 0)) {
3297 if (ctxt->error != NULL)
3298 ctxt->error(ctxt->userData,
3299 "value type '%s' is not an NCName\n",
3300 type);
3301 ctxt->nbErrors++;
3302 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003303 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3304 if (library == NULL)
3305 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3306
3307 def->name = type;
3308 def->ns = library;
3309
3310 lib = (xmlRelaxNGTypeLibraryPtr)
3311 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3312 if (lib == NULL) {
3313 if (ctxt->error != NULL)
3314 ctxt->error(ctxt->userData,
3315 "Use of unregistered type library '%s'\n",
3316 library);
3317 ctxt->nbErrors++;
3318 def->data = NULL;
3319 } else {
3320 def->data = lib;
3321 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003322 if (ctxt->error != NULL)
3323 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003324 "Internal error with type library '%s': no 'have'\n",
3325 library);
3326 ctxt->nbErrors++;
3327 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003328 success = lib->have(lib->data, def->name);
3329 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003330 if (ctxt->error != NULL)
3331 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003332 "Error type '%s' is not exported by type library '%s'\n",
3333 def->name, library);
3334 ctxt->nbErrors++;
3335 }
3336 }
3337 }
3338 }
3339 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00003340 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003341 } else if (((node->children->type != XML_TEXT_NODE) &&
3342 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00003343 (node->children->next != NULL)) {
3344 if (ctxt->error != NULL)
3345 ctxt->error(ctxt->userData,
3346 "Expecting a single text value for <value>content\n");
3347 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003348 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00003349 def->value = xmlNodeGetContent(node);
3350 if (def->value == NULL) {
3351 if (ctxt->error != NULL)
3352 ctxt->error(ctxt->userData,
3353 "Element <value> has no content\n");
3354 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003355 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3356 void *val = NULL;
3357
3358 success = lib->check(lib->data, def->name, def->value, &val, node);
3359 if (success != 1) {
3360 if (ctxt->error != NULL)
3361 ctxt->error(ctxt->userData,
3362 "Value '%s' is not acceptable for type '%s'\n",
3363 def->value, def->name);
3364 ctxt->nbErrors++;
3365 } else {
3366 if (val != NULL)
3367 def->attrs = val;
3368 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003369 }
3370 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003371 return(def);
3372}
3373
3374/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003375 * xmlRelaxNGParseData:
3376 * @ctxt: a Relax-NG parser context
3377 * @node: the data node.
3378 *
3379 * parse the content of a RelaxNG data node.
3380 *
3381 * Returns the definition pointer or NULL in case of error
3382 */
3383static xmlRelaxNGDefinePtr
3384xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003385 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003386 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003387 xmlRelaxNGTypeLibraryPtr lib;
3388 xmlChar *type;
3389 xmlChar *library;
3390 xmlNodePtr content;
3391 int tmp;
3392
3393 type = xmlGetProp(node, BAD_CAST "type");
3394 if (type == NULL) {
3395 if (ctxt->error != NULL)
3396 ctxt->error(ctxt->userData,
3397 "data has no type\n");
3398 ctxt->nbErrors++;
3399 return(NULL);
3400 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003401 xmlRelaxNGNormExtSpace(type);
3402 if (xmlValidateNCName(type, 0)) {
3403 if (ctxt->error != NULL)
3404 ctxt->error(ctxt->userData,
3405 "data type '%s' is not an NCName\n",
3406 type);
3407 ctxt->nbErrors++;
3408 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003409 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3410 if (library == NULL)
3411 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3412
Daniel Veillardfd573f12003-03-16 17:52:32 +00003413 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003414 if (def == NULL) {
3415 xmlFree(type);
3416 return(NULL);
3417 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003418 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003419 def->name = type;
3420 def->ns = library;
3421
3422 lib = (xmlRelaxNGTypeLibraryPtr)
3423 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3424 if (lib == NULL) {
3425 if (ctxt->error != NULL)
3426 ctxt->error(ctxt->userData,
3427 "Use of unregistered type library '%s'\n",
3428 library);
3429 ctxt->nbErrors++;
3430 def->data = NULL;
3431 } else {
3432 def->data = lib;
3433 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003434 if (ctxt->error != NULL)
3435 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003436 "Internal error with type library '%s': no 'have'\n",
3437 library);
3438 ctxt->nbErrors++;
3439 } else {
3440 tmp = lib->have(lib->data, def->name);
3441 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003442 if (ctxt->error != NULL)
3443 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003444 "Error type '%s' is not exported by type library '%s'\n",
3445 def->name, library);
3446 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003447 } else if ((xmlStrEqual(library, BAD_CAST
3448 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3449 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3450 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3451 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003452 }
3453 }
3454 }
3455 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003456
3457 /*
3458 * Handle optional params
3459 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003460 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003461 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3462 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003463 if (xmlStrEqual(library,
3464 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3465 if (ctxt->error != NULL)
3466 ctxt->error(ctxt->userData,
3467 "Type library '%s' does not allow type parameters\n",
3468 library);
3469 ctxt->nbErrors++;
3470 content = content->next;
3471 while ((content != NULL) &&
3472 (xmlStrEqual(content->name, BAD_CAST "param")))
3473 content = content->next;
3474 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003475 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003476 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003477 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003478 param->name = xmlGetProp(content, BAD_CAST "name");
3479 if (param->name == NULL) {
3480 if (ctxt->error != NULL)
3481 ctxt->error(ctxt->userData,
3482 "param has no name\n");
3483 ctxt->nbErrors++;
3484 }
3485 param->value = xmlNodeGetContent(content);
3486 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003487 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003488 } else {
3489 lastparam->next = param;
3490 lastparam = param;
3491 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003492 if (lib != NULL) {
3493 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003494 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003495 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003496 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003497 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003498 /*
3499 * Handle optional except
3500 */
3501 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3502 xmlNodePtr child;
3503 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3504
Daniel Veillardfd573f12003-03-16 17:52:32 +00003505 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003506 if (except == NULL) {
3507 return(def);
3508 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003509 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003510 child = content->children;
3511 if (last == NULL) {
3512 def->content = except;
3513 } else {
3514 last->next = except;
3515 }
3516 if (child == NULL) {
3517 if (ctxt->error != NULL)
3518 ctxt->error(ctxt->userData,
3519 "except has no content\n");
3520 ctxt->nbErrors++;
3521 }
3522 while (child != NULL) {
3523 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3524 if (tmp2 != NULL) {
3525 if (last2 == NULL) {
3526 except->content = last2 = tmp2;
3527 } else {
3528 last2->next = tmp2;
3529 last2 = tmp2;
3530 }
3531 }
3532 child = child->next;
3533 }
3534 content = content->next;
3535 }
3536 /*
3537 * Check there is no unhandled data
3538 */
3539 if (content != NULL) {
3540 if (ctxt->error != NULL)
3541 ctxt->error(ctxt->userData,
3542 "Element data has unexpected content %s\n", content->name);
3543 ctxt->nbErrors++;
3544 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003545
3546 return(def);
3547}
3548
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003549static const xmlChar *invalidName = BAD_CAST "\1";
3550
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003551/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003552 * xmlRelaxNGCompareNameClasses:
3553 * @defs1: the first element/attribute defs
3554 * @defs2: the second element/attribute defs
3555 * @name: the restriction on the name
3556 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003557 *
3558 * Compare the 2 lists of element definitions. The comparison is
3559 * that if both lists do not accept the same QNames, it returns 1
3560 * If the 2 lists can accept the same QName the comparison returns 0
3561 *
3562 * Returns 1 disttinct, 0 if equal
3563 */
3564static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003565xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3566 xmlRelaxNGDefinePtr def2) {
3567 int ret = 1;
3568 xmlNode node;
3569 xmlNs ns;
3570 xmlRelaxNGValidCtxt ctxt;
3571 ctxt.flags = FLAGS_IGNORABLE;
3572
Daniel Veillard42f12e92003-03-07 18:32:59 +00003573 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3574
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003575 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3576 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3577 if (def2->type == XML_RELAXNG_TEXT)
3578 return(1);
3579 if (def1->name != NULL) {
3580 node.name = def1->name;
3581 } else {
3582 node.name = invalidName;
3583 }
3584 node.ns = &ns;
3585 if (def1->ns != NULL) {
3586 if (def1->ns[0] == 0) {
3587 node.ns = NULL;
3588 } else {
3589 ns.href = def1->ns;
3590 }
3591 } else {
3592 ns.href = invalidName;
3593 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003594 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003595 if (def1->nameClass != NULL) {
3596 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3597 } else {
3598 ret = 0;
3599 }
3600 } else {
3601 ret = 1;
3602 }
3603 } else if (def1->type == XML_RELAXNG_TEXT) {
3604 if (def2->type == XML_RELAXNG_TEXT)
3605 return(0);
3606 return(1);
3607 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003608 TODO
3609 ret = 0;
3610 } else {
3611 TODO
3612 ret = 0;
3613 }
3614 if (ret == 0)
3615 return(ret);
3616 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3617 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3618 if (def2->name != NULL) {
3619 node.name = def2->name;
3620 } else {
3621 node.name = invalidName;
3622 }
3623 node.ns = &ns;
3624 if (def2->ns != NULL) {
3625 if (def2->ns[0] == 0) {
3626 node.ns = NULL;
3627 } else {
3628 ns.href = def2->ns;
3629 }
3630 } else {
3631 ns.href = invalidName;
3632 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003633 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003634 if (def2->nameClass != NULL) {
3635 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3636 } else {
3637 ret = 0;
3638 }
3639 } else {
3640 ret = 1;
3641 }
3642 } else {
3643 TODO
3644 ret = 0;
3645 }
3646
3647 return(ret);
3648}
3649
3650/**
3651 * xmlRelaxNGCompareElemDefLists:
3652 * @ctxt: a Relax-NG parser context
3653 * @defs1: the first list of element/attribute defs
3654 * @defs2: the second list of element/attribute defs
3655 *
3656 * Compare the 2 lists of element or attribute definitions. The comparison
3657 * is that if both lists do not accept the same QNames, it returns 1
3658 * If the 2 lists can accept the same QName the comparison returns 0
3659 *
3660 * Returns 1 disttinct, 0 if equal
3661 */
3662static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003663xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3664 xmlRelaxNGDefinePtr *def1,
3665 xmlRelaxNGDefinePtr *def2) {
3666 xmlRelaxNGDefinePtr *basedef2 = def2;
3667
Daniel Veillard154877e2003-01-30 12:17:05 +00003668 if ((def1 == NULL) || (def2 == NULL))
3669 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003670 if ((*def1 == NULL) || (*def2 == NULL))
3671 return(1);
3672 while (*def1 != NULL) {
3673 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003674 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3675 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003676 def2++;
3677 }
3678 def2 = basedef2;
3679 def1++;
3680 }
3681 return(1);
3682}
3683
3684/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003685 * xmlRelaxNGGenerateAttributes:
3686 * @ctxt: a Relax-NG parser context
3687 * @def: the definition definition
3688 *
3689 * Check if the definition can only generate attributes
3690 *
3691 * Returns 1 if yes, 0 if no and -1 in case of error.
3692 */
3693static int
3694xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3695 xmlRelaxNGDefinePtr def) {
3696 xmlRelaxNGDefinePtr parent, cur, tmp;
3697
3698 /*
3699 * Don't run that check in case of error. Infinite recursion
3700 * becomes possible.
3701 */
3702 if (ctxt->nbErrors != 0)
3703 return(-1);
3704
3705 parent = NULL;
3706 cur = def;
3707 while (cur != NULL) {
3708 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3709 (cur->type == XML_RELAXNG_TEXT) ||
3710 (cur->type == XML_RELAXNG_DATATYPE) ||
3711 (cur->type == XML_RELAXNG_PARAM) ||
3712 (cur->type == XML_RELAXNG_LIST) ||
3713 (cur->type == XML_RELAXNG_VALUE) ||
3714 (cur->type == XML_RELAXNG_EMPTY))
3715 return(0);
3716 if ((cur->type == XML_RELAXNG_CHOICE) ||
3717 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3718 (cur->type == XML_RELAXNG_GROUP) ||
3719 (cur->type == XML_RELAXNG_ONEORMORE) ||
3720 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3721 (cur->type == XML_RELAXNG_OPTIONAL) ||
3722 (cur->type == XML_RELAXNG_PARENTREF) ||
3723 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3724 (cur->type == XML_RELAXNG_REF) ||
3725 (cur->type == XML_RELAXNG_DEF)) {
3726 if (cur->content != NULL) {
3727 parent = cur;
3728 cur = cur->content;
3729 tmp = cur;
3730 while (tmp != NULL) {
3731 tmp->parent = parent;
3732 tmp = tmp->next;
3733 }
3734 continue;
3735 }
3736 }
3737 if (cur == def)
3738 break;
3739 if (cur->next != NULL) {
3740 cur = cur->next;
3741 continue;
3742 }
3743 do {
3744 cur = cur->parent;
3745 if (cur == NULL) break;
3746 if (cur == def) return(1);
3747 if (cur->next != NULL) {
3748 cur = cur->next;
3749 break;
3750 }
3751 } while (cur != NULL);
3752 }
3753 return(1);
3754}
3755
3756/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003757 * xmlRelaxNGGetElements:
3758 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003759 * @def: the definition definition
3760 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003761 *
3762 * Compute the list of top elements a definition can generate
3763 *
3764 * Returns a list of elements or NULL if none was found.
3765 */
3766static xmlRelaxNGDefinePtr *
3767xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003768 xmlRelaxNGDefinePtr def,
3769 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003770 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003771 int len = 0;
3772 int max = 0;
3773
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003774 /*
3775 * Don't run that check in case of error. Infinite recursion
3776 * becomes possible.
3777 */
3778 if (ctxt->nbErrors != 0)
3779 return(NULL);
3780
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003781 parent = NULL;
3782 cur = def;
3783 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003784 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3785 (cur->type == XML_RELAXNG_TEXT))) ||
3786 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003787 if (ret == NULL) {
3788 max = 10;
3789 ret = (xmlRelaxNGDefinePtr *)
3790 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3791 if (ret == NULL) {
3792 if (ctxt->error != NULL)
3793 ctxt->error(ctxt->userData,
3794 "Out of memory in element search\n");
3795 ctxt->nbErrors++;
3796 return(NULL);
3797 }
3798 } else if (max <= len) {
3799 max *= 2;
3800 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3801 if (ret == NULL) {
3802 if (ctxt->error != NULL)
3803 ctxt->error(ctxt->userData,
3804 "Out of memory in element search\n");
3805 ctxt->nbErrors++;
3806 return(NULL);
3807 }
3808 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003809 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003810 ret[len] = NULL;
3811 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3812 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3813 (cur->type == XML_RELAXNG_GROUP) ||
3814 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003815 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3816 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003817 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003818 (cur->type == XML_RELAXNG_REF) ||
3819 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003820 /*
3821 * Don't go within elements or attributes or string values.
3822 * Just gather the element top list
3823 */
3824 if (cur->content != NULL) {
3825 parent = cur;
3826 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003827 tmp = cur;
3828 while (tmp != NULL) {
3829 tmp->parent = parent;
3830 tmp = tmp->next;
3831 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003832 continue;
3833 }
3834 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003835 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003836 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003837 if (cur->next != NULL) {
3838 cur = cur->next;
3839 continue;
3840 }
3841 do {
3842 cur = cur->parent;
3843 if (cur == NULL) break;
3844 if (cur == def) return(ret);
3845 if (cur->next != NULL) {
3846 cur = cur->next;
3847 break;
3848 }
3849 } while (cur != NULL);
3850 }
3851 return(ret);
3852}
3853
3854/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003855 * xmlRelaxNGCheckChoiceDeterminism:
3856 * @ctxt: a Relax-NG parser context
3857 * @def: the choice definition
3858 *
3859 * Also used to find indeterministic pattern in choice
3860 */
3861static void
3862xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3863 xmlRelaxNGDefinePtr def) {
3864 xmlRelaxNGDefinePtr **list;
3865 xmlRelaxNGDefinePtr cur;
3866 int nbchild = 0, i, j, ret;
3867 int is_nullable = 0;
3868 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003869 xmlHashTablePtr triage = NULL;
3870 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003871
3872 if ((def == NULL) ||
3873 (def->type != XML_RELAXNG_CHOICE))
3874 return;
3875
Daniel Veillarde063f482003-03-21 16:53:17 +00003876 if (def->dflags & IS_PROCESSED)
3877 return;
3878
Daniel Veillardfd573f12003-03-16 17:52:32 +00003879 /*
3880 * Don't run that check in case of error. Infinite recursion
3881 * becomes possible.
3882 */
3883 if (ctxt->nbErrors != 0)
3884 return;
3885
3886 is_nullable = xmlRelaxNGIsNullable(def);
3887
3888 cur = def->content;
3889 while (cur != NULL) {
3890 nbchild++;
3891 cur = cur->next;
3892 }
3893
3894 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3895 sizeof(xmlRelaxNGDefinePtr *));
3896 if (list == NULL) {
3897 if (ctxt->error != NULL)
3898 ctxt->error(ctxt->userData,
3899 "Out of memory in choice computation\n");
3900 ctxt->nbErrors++;
3901 return;
3902 }
3903 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003904 /*
3905 * a bit strong but safe
3906 */
3907 if (is_nullable == 0) {
3908 triage = xmlHashCreate(10);
3909 } else {
3910 is_triable = 0;
3911 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003912 cur = def->content;
3913 while (cur != NULL) {
3914 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003915 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3916 is_triable = 0;
3917 } else if (is_triable == 1) {
3918 xmlRelaxNGDefinePtr *tmp;
3919 int res;
3920
3921 tmp = list[i];
3922 while ((*tmp != NULL) && (is_triable == 1)) {
3923 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3924 res = xmlHashAddEntry2(triage,
3925 BAD_CAST "#text", NULL,
3926 (void *)cur);
3927 if (res != 0)
3928 is_triable = -1;
3929 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3930 ((*tmp)->name != NULL)) {
3931 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3932 res = xmlHashAddEntry2(triage,
3933 (*tmp)->name, NULL,
3934 (void *)cur);
3935 else
3936 res = xmlHashAddEntry2(triage,
3937 (*tmp)->name, (*tmp)->ns,
3938 (void *)cur);
3939 if (res != 0)
3940 is_triable = -1;
3941 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3942 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3943 res = xmlHashAddEntry2(triage,
3944 BAD_CAST "#any", NULL,
3945 (void *)cur);
3946 else
3947 res = xmlHashAddEntry2(triage,
3948 BAD_CAST "#any", (*tmp)->ns,
3949 (void *)cur);
3950 if (res != 0)
3951 is_triable = -1;
3952 } else {
3953 is_triable = -1;
3954 }
3955 tmp++;
3956 }
3957 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003958 i++;
3959 cur = cur->next;
3960 }
3961
3962 for (i = 0;i < nbchild;i++) {
3963 if (list[i] == NULL)
3964 continue;
3965 for (j = 0;j < i;j++) {
3966 if (list[j] == NULL)
3967 continue;
3968 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3969 if (ret == 0) {
3970 is_indeterminist = 1;
3971 }
3972 }
3973 }
3974 for (i = 0;i < nbchild;i++) {
3975 if (list[i] != NULL)
3976 xmlFree(list[i]);
3977 }
3978
3979 xmlFree(list);
3980 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003981 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003982 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003983 if (is_triable == 1) {
3984 def->dflags |= IS_TRIABLE;
3985 def->data = triage;
3986 } else if (triage != NULL) {
3987 xmlHashFree(triage, NULL);
3988 }
3989 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003990}
3991
3992/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003993 * xmlRelaxNGCheckGroupAttrs:
3994 * @ctxt: a Relax-NG parser context
3995 * @def: the group definition
3996 *
3997 * Detects violations of rule 7.3
3998 */
3999static void
4000xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4001 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004002 xmlRelaxNGDefinePtr **list;
4003 xmlRelaxNGDefinePtr cur;
4004 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004005
4006 if ((def == NULL) ||
4007 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00004008 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004009 return;
4010
Daniel Veillarde063f482003-03-21 16:53:17 +00004011 if (def->dflags & IS_PROCESSED)
4012 return;
4013
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004014 /*
4015 * Don't run that check in case of error. Infinite recursion
4016 * becomes possible.
4017 */
4018 if (ctxt->nbErrors != 0)
4019 return;
4020
Daniel Veillardfd573f12003-03-16 17:52:32 +00004021 cur = def->attrs;
4022 while (cur != NULL) {
4023 nbchild++;
4024 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004025 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004026 cur = def->content;
4027 while (cur != NULL) {
4028 nbchild++;
4029 cur = cur->next;
4030 }
4031
4032 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4033 sizeof(xmlRelaxNGDefinePtr *));
4034 if (list == NULL) {
4035 if (ctxt->error != NULL)
4036 ctxt->error(ctxt->userData,
4037 "Out of memory in group computation\n");
4038 ctxt->nbErrors++;
4039 return;
4040 }
4041 i = 0;
4042 cur = def->attrs;
4043 while (cur != NULL) {
4044 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4045 i++;
4046 cur = cur->next;
4047 }
4048 cur = def->content;
4049 while (cur != NULL) {
4050 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4051 i++;
4052 cur = cur->next;
4053 }
4054
4055 for (i = 0;i < nbchild;i++) {
4056 if (list[i] == NULL)
4057 continue;
4058 for (j = 0;j < i;j++) {
4059 if (list[j] == NULL)
4060 continue;
4061 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4062 if (ret == 0) {
4063 if (ctxt->error != NULL)
4064 ctxt->error(ctxt->userData,
4065 "Attributes conflicts in group\n");
4066 ctxt->nbErrors++;
4067 }
4068 }
4069 }
4070 for (i = 0;i < nbchild;i++) {
4071 if (list[i] != NULL)
4072 xmlFree(list[i]);
4073 }
4074
4075 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004076 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004077}
4078
4079/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004080 * xmlRelaxNGComputeInterleaves:
4081 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004082 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004083 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004084 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004085 * A lot of work for preprocessing interleave definitions
4086 * is potentially needed to get a decent execution speed at runtime
4087 * - trying to get a total order on the element nodes generated
4088 * by the interleaves, order the list of interleave definitions
4089 * following that order.
4090 * - if <text/> is used to handle mixed content, it is better to
4091 * flag this in the define and simplify the runtime checking
4092 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004093 */
4094static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004095xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4096 xmlRelaxNGParserCtxtPtr ctxt,
4097 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004098 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004099
Daniel Veillardfd573f12003-03-16 17:52:32 +00004100 xmlRelaxNGPartitionPtr partitions = NULL;
4101 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4102 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004103 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004104 int nbgroups = 0;
4105 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004106 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004107 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004108
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004109 /*
4110 * Don't run that check in case of error. Infinite recursion
4111 * becomes possible.
4112 */
4113 if (ctxt->nbErrors != 0)
4114 return;
4115
Daniel Veillardfd573f12003-03-16 17:52:32 +00004116#ifdef DEBUG_INTERLEAVE
4117 xmlGenericError(xmlGenericErrorContext,
4118 "xmlRelaxNGComputeInterleaves(%s)\n",
4119 name);
4120#endif
4121 cur = def->content;
4122 while (cur != NULL) {
4123 nbchild++;
4124 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004125 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004126
4127#ifdef DEBUG_INTERLEAVE
4128 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4129#endif
4130 groups = (xmlRelaxNGInterleaveGroupPtr *)
4131 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4132 if (groups == NULL)
4133 goto error;
4134 cur = def->content;
4135 while (cur != NULL) {
4136 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4137 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4138 if (groups[nbgroups] == NULL)
4139 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004140 if (cur->type == XML_RELAXNG_TEXT)
4141 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004142 groups[nbgroups]->rule = cur;
4143 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4144 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4145 nbgroups++;
4146 cur = cur->next;
4147 }
4148#ifdef DEBUG_INTERLEAVE
4149 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4150#endif
4151
4152 /*
4153 * Let's check that all rules makes a partitions according to 7.4
4154 */
4155 partitions = (xmlRelaxNGPartitionPtr)
4156 xmlMalloc(sizeof(xmlRelaxNGPartition));
4157 if (partitions == NULL)
4158 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004159 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004160 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004161 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162 for (i = 0;i < nbgroups;i++) {
4163 group = groups[i];
4164 for (j = i+1;j < nbgroups;j++) {
4165 if (groups[j] == NULL)
4166 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004167
Daniel Veillardfd573f12003-03-16 17:52:32 +00004168 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4169 groups[j]->defs);
4170 if (ret == 0) {
4171 if (ctxt->error != NULL)
4172 ctxt->error(ctxt->userData,
4173 "Element or text conflicts in interleave\n");
4174 ctxt->nbErrors++;
4175 }
4176 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4177 groups[j]->attrs);
4178 if (ret == 0) {
4179 if (ctxt->error != NULL)
4180 ctxt->error(ctxt->userData,
4181 "Attributes conflicts in interleave\n");
4182 ctxt->nbErrors++;
4183 }
4184 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004185 tmp = group->defs;
4186 if ((tmp != NULL) && (*tmp != NULL)) {
4187 while (*tmp != NULL) {
4188 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4189 res = xmlHashAddEntry2(partitions->triage,
4190 BAD_CAST "#text", NULL,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004191 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004192 if (res != 0)
4193 is_determinist = -1;
4194 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4195 ((*tmp)->name != NULL)) {
4196 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4197 res = xmlHashAddEntry2(partitions->triage,
4198 (*tmp)->name, NULL,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004199 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004200 else
4201 res = xmlHashAddEntry2(partitions->triage,
4202 (*tmp)->name, (*tmp)->ns,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004203 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004204 if (res != 0)
4205 is_determinist = -1;
4206 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4207 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4208 res = xmlHashAddEntry2(partitions->triage,
4209 BAD_CAST "#any", NULL,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004210 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004211 else
4212 res = xmlHashAddEntry2(partitions->triage,
4213 BAD_CAST "#any", (*tmp)->ns,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004214 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004215 if ((*tmp)->nameClass != NULL)
4216 is_determinist = 2;
4217 if (res != 0)
4218 is_determinist = -1;
4219 } else {
4220 is_determinist = -1;
4221 }
4222 tmp++;
4223 }
4224 } else {
4225 is_determinist = 0;
4226 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004227 }
4228 partitions->groups = groups;
4229
4230 /*
4231 * and save the partition list back in the def
4232 */
4233 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004234 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00004235 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004236 if (is_determinist == 1)
4237 partitions->flags = IS_DETERMINIST;
4238 if (is_determinist == 2)
4239 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004240 return;
4241
4242error:
4243 if (ctxt->error != NULL)
4244 ctxt->error(ctxt->userData,
4245 "Out of memory in interleave computation\n");
4246 ctxt->nbErrors++;
4247 if (groups != NULL) {
4248 for (i = 0;i < nbgroups;i++)
4249 if (groups[i] != NULL) {
4250 if (groups[i]->defs != NULL)
4251 xmlFree(groups[i]->defs);
4252 xmlFree(groups[i]);
4253 }
4254 xmlFree(groups);
4255 }
4256 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004257}
4258
4259/**
4260 * xmlRelaxNGParseInterleave:
4261 * @ctxt: a Relax-NG parser context
4262 * @node: the data node.
4263 *
4264 * parse the content of a RelaxNG interleave node.
4265 *
4266 * Returns the definition pointer or NULL in case of error
4267 */
4268static xmlRelaxNGDefinePtr
4269xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4270 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004271 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004272 xmlNodePtr child;
4273
Daniel Veillardfd573f12003-03-16 17:52:32 +00004274 def = xmlRelaxNGNewDefine(ctxt, node);
4275 if (def == NULL) {
4276 return(NULL);
4277 }
4278 def->type = XML_RELAXNG_INTERLEAVE;
4279
4280 if (ctxt->interleaves == NULL)
4281 ctxt->interleaves = xmlHashCreate(10);
4282 if (ctxt->interleaves == NULL) {
4283 if (ctxt->error != NULL)
4284 ctxt->error(ctxt->userData,
4285 "Failed to create interleaves hash table\n");
4286 ctxt->nbErrors++;
4287 } else {
4288 char name[32];
4289
4290 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4291 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4292 if (ctxt->error != NULL)
4293 ctxt->error(ctxt->userData,
4294 "Failed to add %s to hash table\n", name);
4295 ctxt->nbErrors++;
4296 }
4297 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004298 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004299 if (child == NULL) {
4300 if (ctxt->error != NULL)
4301 ctxt->error(ctxt->userData, "Element interleave is empty\n");
4302 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004303 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004304 while (child != NULL) {
4305 if (IS_RELAXNG(child, "element")) {
4306 cur = xmlRelaxNGParseElement(ctxt, child);
4307 } else {
4308 cur = xmlRelaxNGParsePattern(ctxt, child);
4309 }
4310 if (cur != NULL) {
4311 cur->parent = def;
4312 if (last == NULL) {
4313 def->content = last = cur;
4314 } else {
4315 last->next = cur;
4316 last = cur;
4317 }
4318 }
4319 child = child->next;
4320 }
4321
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004322 return(def);
4323}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004324
4325/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004326 * xmlRelaxNGParseInclude:
4327 * @ctxt: a Relax-NG parser context
4328 * @node: the include node
4329 *
4330 * Integrate the content of an include node in the current grammar
4331 *
4332 * Returns 0 in case of success or -1 in case of error
4333 */
4334static int
4335xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4336 xmlRelaxNGIncludePtr incl;
4337 xmlNodePtr root;
4338 int ret = 0, tmp;
4339
4340 incl = node->_private;
4341 if (incl == NULL) {
4342 if (ctxt->error != NULL)
4343 ctxt->error(ctxt->userData,
4344 "Include node has no data\n");
4345 ctxt->nbErrors++;
4346 return(-1);
4347 }
4348 root = xmlDocGetRootElement(incl->doc);
4349 if (root == NULL) {
4350 if (ctxt->error != NULL)
4351 ctxt->error(ctxt->userData,
4352 "Include document is empty\n");
4353 ctxt->nbErrors++;
4354 return(-1);
4355 }
4356 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4357 if (ctxt->error != NULL)
4358 ctxt->error(ctxt->userData,
4359 "Include document root is not a grammar\n");
4360 ctxt->nbErrors++;
4361 return(-1);
4362 }
4363
4364 /*
4365 * Merge the definition from both the include and the internal list
4366 */
4367 if (root->children != NULL) {
4368 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4369 if (tmp != 0)
4370 ret = -1;
4371 }
4372 if (node->children != NULL) {
4373 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4374 if (tmp != 0)
4375 ret = -1;
4376 }
4377 return(ret);
4378}
4379
4380/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004381 * xmlRelaxNGParseDefine:
4382 * @ctxt: a Relax-NG parser context
4383 * @node: the define node
4384 *
4385 * parse the content of a RelaxNG define element node.
4386 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004387 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004388 */
4389static int
4390xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4391 xmlChar *name;
4392 int ret = 0, tmp;
4393 xmlRelaxNGDefinePtr def;
4394 const xmlChar *olddefine;
4395
4396 name = xmlGetProp(node, BAD_CAST "name");
4397 if (name == NULL) {
4398 if (ctxt->error != NULL)
4399 ctxt->error(ctxt->userData,
4400 "define has no name\n");
4401 ctxt->nbErrors++;
4402 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004403 xmlRelaxNGNormExtSpace(name);
4404 if (xmlValidateNCName(name, 0)) {
4405 if (ctxt->error != NULL)
4406 ctxt->error(ctxt->userData,
4407 "define name '%s' is not an NCName\n",
4408 name);
4409 ctxt->nbErrors++;
4410 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004411 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004412 if (def == NULL) {
4413 xmlFree(name);
4414 return(-1);
4415 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004416 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004417 def->name = name;
4418 if (node->children == NULL) {
4419 if (ctxt->error != NULL)
4420 ctxt->error(ctxt->userData,
4421 "define has no children\n");
4422 ctxt->nbErrors++;
4423 } else {
4424 olddefine = ctxt->define;
4425 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00004426 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004427 ctxt->define = olddefine;
4428 }
4429 if (ctxt->grammar->defs == NULL)
4430 ctxt->grammar->defs = xmlHashCreate(10);
4431 if (ctxt->grammar->defs == NULL) {
4432 if (ctxt->error != NULL)
4433 ctxt->error(ctxt->userData,
4434 "Could not create definition hash\n");
4435 ctxt->nbErrors++;
4436 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004437 } else {
4438 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4439 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00004440 xmlRelaxNGDefinePtr prev;
4441
4442 prev = xmlHashLookup(ctxt->grammar->defs, name);
4443 if (prev == NULL) {
4444 if (ctxt->error != NULL)
4445 ctxt->error(ctxt->userData,
4446 "Internal error on define aggregation of %s\n",
4447 name);
4448 ctxt->nbErrors++;
4449 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00004450 } else {
4451 while (prev->nextHash != NULL)
4452 prev = prev->nextHash;
4453 prev->nextHash = def;
4454 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004455 }
4456 }
4457 }
4458 return(ret);
4459}
4460
4461/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004462 * xmlRelaxNGProcessExternalRef:
4463 * @ctxt: the parser context
4464 * @node: the externlRef node
4465 *
4466 * Process and compile an externlRef node
4467 *
4468 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4469 */
4470static xmlRelaxNGDefinePtr
4471xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4472 xmlRelaxNGDocumentPtr docu;
4473 xmlNodePtr root, tmp;
4474 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004475 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004476 xmlRelaxNGDefinePtr def;
4477
4478 docu = node->_private;
4479 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004481 if (def == NULL)
4482 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004483 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004484
4485 if (docu->content == NULL) {
4486 /*
4487 * Then do the parsing for good
4488 */
4489 root = xmlDocGetRootElement(docu->doc);
4490 if (root == NULL) {
4491 if (ctxt->error != NULL)
4492 ctxt->error(ctxt->userData,
4493 "xmlRelaxNGParse: %s is empty\n",
4494 ctxt->URL);
4495 ctxt->nbErrors++;
4496 return (NULL);
4497 }
4498 /*
4499 * ns transmission rules
4500 */
4501 ns = xmlGetProp(root, BAD_CAST "ns");
4502 if (ns == NULL) {
4503 tmp = node;
4504 while ((tmp != NULL) &&
4505 (tmp->type == XML_ELEMENT_NODE)) {
4506 ns = xmlGetProp(tmp, BAD_CAST "ns");
4507 if (ns != NULL) {
4508 break;
4509 }
4510 tmp = tmp->parent;
4511 }
4512 if (ns != NULL) {
4513 xmlSetProp(root, BAD_CAST "ns", ns);
4514 newNs = 1;
4515 xmlFree(ns);
4516 }
4517 } else {
4518 xmlFree(ns);
4519 }
4520
4521 /*
4522 * Parsing to get a precompiled schemas.
4523 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004524 oldflags = ctxt->flags;
4525 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004526 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004527 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004528 if ((docu->schema != NULL) &&
4529 (docu->schema->topgrammar != NULL)) {
4530 docu->content = docu->schema->topgrammar->start;
4531 }
4532
4533 /*
4534 * the externalRef may be reused in a different ns context
4535 */
4536 if (newNs == 1) {
4537 xmlUnsetProp(root, BAD_CAST "ns");
4538 }
4539 }
4540 def->content = docu->content;
4541 } else {
4542 def = NULL;
4543 }
4544 return(def);
4545}
4546
4547/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004548 * xmlRelaxNGParsePattern:
4549 * @ctxt: a Relax-NG parser context
4550 * @node: the pattern node.
4551 *
4552 * parse the content of a RelaxNG pattern node.
4553 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004554 * Returns the definition pointer or NULL in case of error or if no
4555 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004556 */
4557static xmlRelaxNGDefinePtr
4558xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4559 xmlRelaxNGDefinePtr def = NULL;
4560
Daniel Veillardd2298792003-02-14 16:54:11 +00004561 if (node == NULL) {
4562 return(NULL);
4563 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004564 if (IS_RELAXNG(node, "element")) {
4565 def = xmlRelaxNGParseElement(ctxt, node);
4566 } else if (IS_RELAXNG(node, "attribute")) {
4567 def = xmlRelaxNGParseAttribute(ctxt, node);
4568 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004569 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004570 if (def == NULL)
4571 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004572 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004573 if (node->children != NULL) {
4574 if (ctxt->error != NULL)
4575 ctxt->error(ctxt->userData, "empty: had a child node\n");
4576 ctxt->nbErrors++;
4577 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004578 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004579 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004580 if (def == NULL)
4581 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004582 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004583 if (node->children != NULL) {
4584 if (ctxt->error != NULL)
4585 ctxt->error(ctxt->userData, "text: had a child node\n");
4586 ctxt->nbErrors++;
4587 }
4588 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004589 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004590 if (def == NULL)
4591 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004592 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004593 if (node->children == NULL) {
4594 if (ctxt->error != NULL)
4595 ctxt->error(ctxt->userData,
4596 "Element %s is empty\n", node->name);
4597 ctxt->nbErrors++;
4598 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004599 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004600 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004601 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004602 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004603 if (def == NULL)
4604 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004605 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004606 if (node->children == NULL) {
4607 if (ctxt->error != NULL)
4608 ctxt->error(ctxt->userData,
4609 "Element %s is empty\n", node->name);
4610 ctxt->nbErrors++;
4611 } else {
4612 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4613 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004614 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004615 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004616 if (def == NULL)
4617 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004618 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004619 if (node->children == NULL) {
4620 if (ctxt->error != NULL)
4621 ctxt->error(ctxt->userData,
4622 "Element %s is empty\n", node->name);
4623 ctxt->nbErrors++;
4624 } else {
4625 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4626 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004627 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004628 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004629 if (def == NULL)
4630 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004631 def->type = XML_RELAXNG_CHOICE;
4632 if (node->children == NULL) {
4633 if (ctxt->error != NULL)
4634 ctxt->error(ctxt->userData,
4635 "Element %s is empty\n", node->name);
4636 ctxt->nbErrors++;
4637 } else {
4638 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4639 }
4640 } else if (IS_RELAXNG(node, "group")) {
4641 def = xmlRelaxNGNewDefine(ctxt, node);
4642 if (def == NULL)
4643 return(NULL);
4644 def->type = XML_RELAXNG_GROUP;
4645 if (node->children == NULL) {
4646 if (ctxt->error != NULL)
4647 ctxt->error(ctxt->userData,
4648 "Element %s is empty\n", node->name);
4649 ctxt->nbErrors++;
4650 } else {
4651 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4652 }
4653 } else if (IS_RELAXNG(node, "ref")) {
4654 def = xmlRelaxNGNewDefine(ctxt, node);
4655 if (def == NULL)
4656 return(NULL);
4657 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004658 def->name = xmlGetProp(node, BAD_CAST "name");
4659 if (def->name == NULL) {
4660 if (ctxt->error != NULL)
4661 ctxt->error(ctxt->userData,
4662 "ref has no name\n");
4663 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004664 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004665 xmlRelaxNGNormExtSpace(def->name);
4666 if (xmlValidateNCName(def->name, 0)) {
4667 if (ctxt->error != NULL)
4668 ctxt->error(ctxt->userData,
4669 "ref name '%s' is not an NCName\n",
4670 def->name);
4671 ctxt->nbErrors++;
4672 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004673 }
4674 if (node->children != NULL) {
4675 if (ctxt->error != NULL)
4676 ctxt->error(ctxt->userData,
4677 "ref is not empty\n");
4678 ctxt->nbErrors++;
4679 }
4680 if (ctxt->grammar->refs == NULL)
4681 ctxt->grammar->refs = xmlHashCreate(10);
4682 if (ctxt->grammar->refs == NULL) {
4683 if (ctxt->error != NULL)
4684 ctxt->error(ctxt->userData,
4685 "Could not create references hash\n");
4686 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004687 def = NULL;
4688 } else {
4689 int tmp;
4690
4691 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4692 if (tmp < 0) {
4693 xmlRelaxNGDefinePtr prev;
4694
4695 prev = (xmlRelaxNGDefinePtr)
4696 xmlHashLookup(ctxt->grammar->refs, def->name);
4697 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004698 if (def->name != NULL) {
4699 if (ctxt->error != NULL)
4700 ctxt->error(ctxt->userData,
4701 "Error refs definitions '%s'\n",
4702 def->name);
4703 } else {
4704 if (ctxt->error != NULL)
4705 ctxt->error(ctxt->userData,
4706 "Error refs definitions\n");
4707 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004708 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004709 def = NULL;
4710 } else {
4711 def->nextHash = prev->nextHash;
4712 prev->nextHash = def;
4713 }
4714 }
4715 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004716 } else if (IS_RELAXNG(node, "data")) {
4717 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004718 } else if (IS_RELAXNG(node, "value")) {
4719 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004720 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004721 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004722 if (def == NULL)
4723 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004724 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004725 if (node->children == NULL) {
4726 if (ctxt->error != NULL)
4727 ctxt->error(ctxt->userData,
4728 "Element %s is empty\n", node->name);
4729 ctxt->nbErrors++;
4730 } else {
4731 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4732 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004733 } else if (IS_RELAXNG(node, "interleave")) {
4734 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004735 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004736 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004737 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004738 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004739 if (def == NULL)
4740 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004741 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004742 if (node->children != NULL) {
4743 if (ctxt->error != NULL)
4744 ctxt->error(ctxt->userData,
4745 "xmlRelaxNGParse: notAllowed element is not empty\n");
4746 ctxt->nbErrors++;
4747 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004748 } else if (IS_RELAXNG(node, "grammar")) {
4749 xmlRelaxNGGrammarPtr grammar, old;
4750 xmlRelaxNGGrammarPtr oldparent;
4751
Daniel Veillardc482e262003-02-26 14:48:48 +00004752#ifdef DEBUG_GRAMMAR
4753 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4754#endif
4755
Daniel Veillard419a7682003-02-03 23:22:49 +00004756 oldparent = ctxt->parentgrammar;
4757 old = ctxt->grammar;
4758 ctxt->parentgrammar = old;
4759 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4760 if (old != NULL) {
4761 ctxt->grammar = old;
4762 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004763#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004764 if (grammar != NULL) {
4765 grammar->next = old->next;
4766 old->next = grammar;
4767 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004768#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004769 }
4770 if (grammar != NULL)
4771 def = grammar->start;
4772 else
4773 def = NULL;
4774 } else if (IS_RELAXNG(node, "parentRef")) {
4775 if (ctxt->parentgrammar == NULL) {
4776 if (ctxt->error != NULL)
4777 ctxt->error(ctxt->userData,
4778 "Use of parentRef without a parent grammar\n");
4779 ctxt->nbErrors++;
4780 return(NULL);
4781 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004782 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004783 if (def == NULL)
4784 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004785 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004786 def->name = xmlGetProp(node, BAD_CAST "name");
4787 if (def->name == NULL) {
4788 if (ctxt->error != NULL)
4789 ctxt->error(ctxt->userData,
4790 "parentRef has no name\n");
4791 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004792 } else {
4793 xmlRelaxNGNormExtSpace(def->name);
4794 if (xmlValidateNCName(def->name, 0)) {
4795 if (ctxt->error != NULL)
4796 ctxt->error(ctxt->userData,
4797 "parentRef name '%s' is not an NCName\n",
4798 def->name);
4799 ctxt->nbErrors++;
4800 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004801 }
4802 if (node->children != NULL) {
4803 if (ctxt->error != NULL)
4804 ctxt->error(ctxt->userData,
4805 "parentRef is not empty\n");
4806 ctxt->nbErrors++;
4807 }
4808 if (ctxt->parentgrammar->refs == NULL)
4809 ctxt->parentgrammar->refs = xmlHashCreate(10);
4810 if (ctxt->parentgrammar->refs == NULL) {
4811 if (ctxt->error != NULL)
4812 ctxt->error(ctxt->userData,
4813 "Could not create references hash\n");
4814 ctxt->nbErrors++;
4815 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004816 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004817 int tmp;
4818
4819 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4820 if (tmp < 0) {
4821 xmlRelaxNGDefinePtr prev;
4822
4823 prev = (xmlRelaxNGDefinePtr)
4824 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4825 if (prev == NULL) {
4826 if (ctxt->error != NULL)
4827 ctxt->error(ctxt->userData,
4828 "Internal error parentRef definitions '%s'\n",
4829 def->name);
4830 ctxt->nbErrors++;
4831 def = NULL;
4832 } else {
4833 def->nextHash = prev->nextHash;
4834 prev->nextHash = def;
4835 }
4836 }
4837 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004838 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004839 if (node->children == NULL) {
4840 if (ctxt->error != NULL)
4841 ctxt->error(ctxt->userData,
4842 "Mixed is empty\n");
4843 ctxt->nbErrors++;
4844 def = NULL;
4845 } else {
4846 def = xmlRelaxNGParseInterleave(ctxt, node);
4847 if (def != NULL) {
4848 xmlRelaxNGDefinePtr tmp;
4849
4850 if ((def->content != NULL) && (def->content->next != NULL)) {
4851 tmp = xmlRelaxNGNewDefine(ctxt, node);
4852 if (tmp != NULL) {
4853 tmp->type = XML_RELAXNG_GROUP;
4854 tmp->content = def->content;
4855 def->content = tmp;
4856 }
4857 }
4858
4859 tmp = xmlRelaxNGNewDefine(ctxt, node);
4860 if (tmp == NULL)
4861 return(def);
4862 tmp->type = XML_RELAXNG_TEXT;
4863 tmp->next = def->content;
4864 def->content = tmp;
4865 }
4866 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004867 } else {
4868 if (ctxt->error != NULL)
4869 ctxt->error(ctxt->userData,
4870 "Unexpected node %s is not a pattern\n",
4871 node->name);
4872 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004873 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004874 }
4875 return(def);
4876}
4877
4878/**
4879 * xmlRelaxNGParseAttribute:
4880 * @ctxt: a Relax-NG parser context
4881 * @node: the element node
4882 *
4883 * parse the content of a RelaxNG attribute node.
4884 *
4885 * Returns the definition pointer or NULL in case of error.
4886 */
4887static xmlRelaxNGDefinePtr
4888xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004889 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004890 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004891 int old_flags;
4892
Daniel Veillardfd573f12003-03-16 17:52:32 +00004893 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004894 if (ret == NULL)
4895 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004896 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004897 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004898 child = node->children;
4899 if (child == NULL) {
4900 if (ctxt->error != NULL)
4901 ctxt->error(ctxt->userData,
4902 "xmlRelaxNGParseattribute: attribute has no children\n");
4903 ctxt->nbErrors++;
4904 return(ret);
4905 }
4906 old_flags = ctxt->flags;
4907 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004908 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4909 if (cur != NULL)
4910 child = child->next;
4911
Daniel Veillardd2298792003-02-14 16:54:11 +00004912 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004913 cur = xmlRelaxNGParsePattern(ctxt, child);
4914 if (cur != NULL) {
4915 switch (cur->type) {
4916 case XML_RELAXNG_EMPTY:
4917 case XML_RELAXNG_NOT_ALLOWED:
4918 case XML_RELAXNG_TEXT:
4919 case XML_RELAXNG_ELEMENT:
4920 case XML_RELAXNG_DATATYPE:
4921 case XML_RELAXNG_VALUE:
4922 case XML_RELAXNG_LIST:
4923 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004924 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004925 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004926 case XML_RELAXNG_DEF:
4927 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004928 case XML_RELAXNG_ZEROORMORE:
4929 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004930 case XML_RELAXNG_CHOICE:
4931 case XML_RELAXNG_GROUP:
4932 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004933 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004934 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004935 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004936 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004937 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004938 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004939 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004940 if (ctxt->error != NULL)
4941 ctxt->error(ctxt->userData,
4942 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004943 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004944 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004945 case XML_RELAXNG_NOOP:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004946 if (ctxt->error != NULL)
4947 ctxt->error(ctxt->userData,
Daniel Veillardac297932003-04-17 12:55:35 +00004948 "RNG Internal error, noop found in attribute\n");
Daniel Veillard77648bb2003-02-20 15:03:22 +00004949 ctxt->nbErrors++;
4950 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004951 }
4952 }
4953 child = child->next;
4954 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004955 if (child != NULL) {
4956 if (ctxt->error != NULL)
4957 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4958 ctxt->nbErrors++;
4959 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004960 ctxt->flags = old_flags;
4961 return(ret);
4962}
4963
4964/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004965 * xmlRelaxNGParseExceptNameClass:
4966 * @ctxt: a Relax-NG parser context
4967 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004968 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004969 *
4970 * parse the content of a RelaxNG nameClass node.
4971 *
4972 * Returns the definition pointer or NULL in case of error.
4973 */
4974static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004975xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4976 xmlNodePtr node, int attr) {
4977 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4978 xmlNodePtr child;
4979
Daniel Veillardd2298792003-02-14 16:54:11 +00004980 if (!IS_RELAXNG(node, "except")) {
4981 if (ctxt->error != NULL)
4982 ctxt->error(ctxt->userData,
4983 "Expecting an except node\n");
4984 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004985 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004986 }
4987 if (node->next != NULL) {
4988 if (ctxt->error != NULL)
4989 ctxt->error(ctxt->userData,
4990 "exceptNameClass allows only a single except node\n");
4991 ctxt->nbErrors++;
4992 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004993 if (node->children == NULL) {
4994 if (ctxt->error != NULL)
4995 ctxt->error(ctxt->userData,
4996 "except has no content\n");
4997 ctxt->nbErrors++;
4998 return(NULL);
4999 }
5000
Daniel Veillardfd573f12003-03-16 17:52:32 +00005001 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005002 if (ret == NULL)
5003 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005004 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005005 child = node->children;
5006 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005007 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00005008 if (cur == NULL)
5009 break;
5010 if (attr)
5011 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005012 else
5013 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005014
Daniel Veillard419a7682003-02-03 23:22:49 +00005015 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00005016 if (last == NULL) {
5017 ret->content = cur;
5018 } else {
5019 last->next = cur;
5020 }
5021 last = cur;
5022 }
5023 child = child->next;
5024 }
5025
5026 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005027}
5028
5029/**
5030 * xmlRelaxNGParseNameClass:
5031 * @ctxt: a Relax-NG parser context
5032 * @node: the nameClass node
5033 * @def: the current definition
5034 *
5035 * parse the content of a RelaxNG nameClass node.
5036 *
5037 * Returns the definition pointer or NULL in case of error.
5038 */
5039static xmlRelaxNGDefinePtr
5040xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5041 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005042 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005043 xmlChar *val;
5044
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005045 ret = def;
5046 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5047 (IS_RELAXNG(node, "nsName"))) {
5048 if ((def->type != XML_RELAXNG_ELEMENT) &&
5049 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005050 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005051 if (ret == NULL)
5052 return(NULL);
5053 ret->parent = def;
5054 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5055 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005056 else
5057 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005058 }
5059 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005060 if (IS_RELAXNG(node, "name")) {
5061 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00005062 xmlRelaxNGNormExtSpace(val);
5063 if (xmlValidateNCName(val, 0)) {
5064 if (ctxt->error != NULL) {
5065 if (node->parent != NULL)
5066 ctxt->error(ctxt->userData,
5067 "Element %s name '%s' is not an NCName\n",
5068 node->parent->name, val);
5069 else
5070 ctxt->error(ctxt->userData,
5071 "name '%s' is not an NCName\n",
5072 val);
5073 }
5074 ctxt->nbErrors++;
5075 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005076 ret->name = val;
5077 val = xmlGetProp(node, BAD_CAST "ns");
5078 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00005079 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5080 (val != NULL) &&
5081 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5082 ctxt->error(ctxt->userData,
5083 "Attribute with namespace '%s' is not allowed\n",
5084 val);
5085 ctxt->nbErrors++;
5086 }
5087 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5088 (val != NULL) &&
5089 (val[0] == 0) &&
5090 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5091 ctxt->error(ctxt->userData,
5092 "Attribute with QName 'xmlns' is not allowed\n",
5093 val);
5094 ctxt->nbErrors++;
5095 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005096 } else if (IS_RELAXNG(node, "anyName")) {
5097 ret->name = NULL;
5098 ret->ns = NULL;
5099 if (node->children != NULL) {
5100 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005101 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5102 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005103 }
5104 } else if (IS_RELAXNG(node, "nsName")) {
5105 ret->name = NULL;
5106 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5107 if (ret->ns == NULL) {
5108 if (ctxt->error != NULL)
5109 ctxt->error(ctxt->userData,
5110 "nsName has no ns attribute\n");
5111 ctxt->nbErrors++;
5112 }
Daniel Veillard416589a2003-02-17 17:25:42 +00005113 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5114 (ret->ns != NULL) &&
5115 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5116 ctxt->error(ctxt->userData,
5117 "Attribute with namespace '%s' is not allowed\n",
5118 ret->ns);
5119 ctxt->nbErrors++;
5120 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005121 if (node->children != NULL) {
5122 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005123 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5124 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005125 }
5126 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005127 xmlNodePtr child;
5128 xmlRelaxNGDefinePtr last = NULL;
5129
5130 ret = xmlRelaxNGNewDefine(ctxt, node);
5131 if (ret == NULL)
5132 return(NULL);
5133 ret->parent = def;
5134 ret->type = XML_RELAXNG_CHOICE;
5135
Daniel Veillardd2298792003-02-14 16:54:11 +00005136 if (node->children == NULL) {
5137 if (ctxt->error != NULL)
5138 ctxt->error(ctxt->userData,
5139 "Element choice is empty\n");
5140 ctxt->nbErrors++;
5141 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005142
5143 child = node->children;
5144 while (child != NULL) {
5145 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5146 if (tmp != NULL) {
5147 if (last == NULL) {
5148 last = ret->nameClass = tmp;
5149 } else {
5150 last->next = tmp;
5151 last = tmp;
5152 }
5153 }
5154 child = child->next;
5155 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005156 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005157 } else {
5158 if (ctxt->error != NULL)
5159 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00005160 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005161 node->name);
5162 ctxt->nbErrors++;
5163 return(NULL);
5164 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005165 if (ret != def) {
5166 if (def->nameClass == NULL) {
5167 def->nameClass = ret;
5168 } else {
5169 tmp = def->nameClass;
5170 while (tmp->next != NULL) {
5171 tmp = tmp->next;
5172 }
5173 tmp->next = ret;
5174 }
5175 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005176 return(ret);
5177}
5178
5179/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005180 * xmlRelaxNGParseElement:
5181 * @ctxt: a Relax-NG parser context
5182 * @node: the element node
5183 *
5184 * parse the content of a RelaxNG element node.
5185 *
5186 * Returns the definition pointer or NULL in case of error.
5187 */
5188static xmlRelaxNGDefinePtr
5189xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5190 xmlRelaxNGDefinePtr ret, cur, last;
5191 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005192 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005193
Daniel Veillardfd573f12003-03-16 17:52:32 +00005194 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005195 if (ret == NULL)
5196 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005197 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005198 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005199 child = node->children;
5200 if (child == NULL) {
5201 if (ctxt->error != NULL)
5202 ctxt->error(ctxt->userData,
5203 "xmlRelaxNGParseElement: element has no children\n");
5204 ctxt->nbErrors++;
5205 return(ret);
5206 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005207 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5208 if (cur != NULL)
5209 child = child->next;
5210
Daniel Veillard6eadf632003-01-23 18:29:16 +00005211 if (child == NULL) {
5212 if (ctxt->error != NULL)
5213 ctxt->error(ctxt->userData,
5214 "xmlRelaxNGParseElement: element has no content\n");
5215 ctxt->nbErrors++;
5216 return(ret);
5217 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005218 olddefine = ctxt->define;
5219 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005220 last = NULL;
5221 while (child != NULL) {
5222 cur = xmlRelaxNGParsePattern(ctxt, child);
5223 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005224 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005225 switch (cur->type) {
5226 case XML_RELAXNG_EMPTY:
5227 case XML_RELAXNG_NOT_ALLOWED:
5228 case XML_RELAXNG_TEXT:
5229 case XML_RELAXNG_ELEMENT:
5230 case XML_RELAXNG_DATATYPE:
5231 case XML_RELAXNG_VALUE:
5232 case XML_RELAXNG_LIST:
5233 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00005234 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005235 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005236 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005237 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005238 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005239 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005240 case XML_RELAXNG_CHOICE:
5241 case XML_RELAXNG_GROUP:
5242 case XML_RELAXNG_INTERLEAVE:
5243 if (last == NULL) {
5244 ret->content = last = cur;
5245 } else {
5246 if ((last->type == XML_RELAXNG_ELEMENT) &&
5247 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005248 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005249 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005250 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005251 ret->content->content = last;
5252 } else {
5253 ret->content = last;
5254 }
5255 }
5256 last->next = cur;
5257 last = cur;
5258 }
5259 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005260 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardce192eb2003-04-16 15:58:05 +00005261 /* HERE !!! */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005262 cur->next = ret->attrs;
5263 ret->attrs = cur;
5264 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005265 case XML_RELAXNG_START:
Daniel Veillardac297932003-04-17 12:55:35 +00005266 if (ctxt->error != NULL)
5267 ctxt->error(ctxt->userData,
5268 "RNG Internal error, start found in element\n");
5269 ctxt->nbErrors++;
5270 break;
Daniel Veillard8fe98712003-02-19 00:19:14 +00005271 case XML_RELAXNG_PARAM:
Daniel Veillardac297932003-04-17 12:55:35 +00005272 if (ctxt->error != NULL)
5273 ctxt->error(ctxt->userData,
5274 "RNG Internal error, param found in element\n");
5275 ctxt->nbErrors++;
5276 break;
Daniel Veillard144fae12003-02-03 13:17:57 +00005277 case XML_RELAXNG_EXCEPT:
Daniel Veillardac297932003-04-17 12:55:35 +00005278 if (ctxt->error != NULL)
5279 ctxt->error(ctxt->userData,
5280 "RNG Internal error, except found in element\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005281 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005282 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00005283 case XML_RELAXNG_NOOP:
Daniel Veillard77648bb2003-02-20 15:03:22 +00005284 if (ctxt->error != NULL)
5285 ctxt->error(ctxt->userData,
Daniel Veillardac297932003-04-17 12:55:35 +00005286 "RNG Internal error, noop found in element\n");
Daniel Veillard77648bb2003-02-20 15:03:22 +00005287 ctxt->nbErrors++;
5288 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005289 }
5290 }
5291 child = child->next;
5292 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005293 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005294 return(ret);
5295}
5296
5297/**
5298 * xmlRelaxNGParsePatterns:
5299 * @ctxt: a Relax-NG parser context
5300 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005301 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005302 *
5303 * parse the content of a RelaxNG start node.
5304 *
5305 * Returns the definition pointer or NULL in case of error.
5306 */
5307static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005308xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5309 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005310 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005311
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005312 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005313 while (nodes != NULL) {
5314 if (IS_RELAXNG(nodes, "element")) {
5315 cur = xmlRelaxNGParseElement(ctxt, nodes);
5316 if (def == NULL) {
5317 def = last = cur;
5318 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00005319 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5320 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005321 def = xmlRelaxNGNewDefine(ctxt, nodes);
5322 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005323 def->content = last;
5324 }
5325 last->next = cur;
5326 last = cur;
5327 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005328 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005329 } else {
5330 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00005331 if (cur != NULL) {
5332 if (def == NULL) {
5333 def = last = cur;
5334 } else {
5335 last->next = cur;
5336 last = cur;
5337 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005338 }
5339 }
5340 nodes = nodes->next;
5341 }
5342 return(def);
5343}
5344
5345/**
5346 * xmlRelaxNGParseStart:
5347 * @ctxt: a Relax-NG parser context
5348 * @nodes: start children nodes
5349 *
5350 * parse the content of a RelaxNG start node.
5351 *
5352 * Returns 0 in case of success, -1 in case of error
5353 */
5354static int
5355xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5356 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005357 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005358
Daniel Veillardd2298792003-02-14 16:54:11 +00005359 if (nodes == NULL) {
5360 if (ctxt->error != NULL)
5361 ctxt->error(ctxt->userData,
5362 "start has no children\n");
5363 ctxt->nbErrors++;
5364 return(-1);
5365 }
5366 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005367 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005368 if (def == NULL)
5369 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005370 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00005371 if (nodes->children != NULL) {
5372 if (ctxt->error != NULL)
5373 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005374 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005375 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005376 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005377 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005378 if (def == NULL)
5379 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005380 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00005381 if (nodes->children != NULL) {
5382 if (ctxt->error != NULL)
5383 ctxt->error(ctxt->userData,
5384 "element notAllowed is not empty\n");
5385 ctxt->nbErrors++;
5386 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005387 } else {
5388 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005389 }
5390 if (ctxt->grammar->start != NULL) {
5391 last = ctxt->grammar->start;
5392 while (last->next != NULL)
5393 last = last->next;
5394 last->next = def;
5395 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005396 ctxt->grammar->start = def;
5397 }
5398 nodes = nodes->next;
5399 if (nodes != NULL) {
5400 if (ctxt->error != NULL)
5401 ctxt->error(ctxt->userData,
5402 "start more than one children\n");
5403 ctxt->nbErrors++;
5404 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005405 }
5406 return(ret);
5407}
5408
5409/**
5410 * xmlRelaxNGParseGrammarContent:
5411 * @ctxt: a Relax-NG parser context
5412 * @nodes: grammar children nodes
5413 *
5414 * parse the content of a RelaxNG grammar node.
5415 *
5416 * Returns 0 in case of success, -1 in case of error
5417 */
5418static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005419xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005420{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005421 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005422
5423 if (nodes == NULL) {
5424 if (ctxt->error != NULL)
5425 ctxt->error(ctxt->userData,
5426 "grammar has no children\n");
5427 ctxt->nbErrors++;
5428 return(-1);
5429 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005430 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005431 if (IS_RELAXNG(nodes, "start")) {
5432 if (nodes->children == NULL) {
5433 if (ctxt->error != NULL)
5434 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00005435 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005436 ctxt->nbErrors++;
5437 } else {
5438 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5439 if (tmp != 0)
5440 ret = -1;
5441 }
5442 } else if (IS_RELAXNG(nodes, "define")) {
5443 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5444 if (tmp != 0)
5445 ret = -1;
5446 } else if (IS_RELAXNG(nodes, "include")) {
5447 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5448 if (tmp != 0)
5449 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005450 } else {
5451 if (ctxt->error != NULL)
5452 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005453 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005454 ctxt->nbErrors++;
5455 ret = -1;
5456 }
5457 nodes = nodes->next;
5458 }
5459 return (ret);
5460}
5461
5462/**
5463 * xmlRelaxNGCheckReference:
5464 * @ref: the ref
5465 * @ctxt: a Relax-NG parser context
5466 * @name: the name associated to the defines
5467 *
5468 * Applies the 4.17. combine attribute rule for all the define
5469 * element of a given grammar using the same name.
5470 */
5471static void
5472xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5473 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5474 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005475 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005476
5477 grammar = ctxt->grammar;
5478 if (grammar == NULL) {
5479 if (ctxt->error != NULL)
5480 ctxt->error(ctxt->userData,
5481 "Internal error: no grammar in CheckReference %s\n",
5482 name);
5483 ctxt->nbErrors++;
5484 return;
5485 }
5486 if (ref->content != NULL) {
5487 if (ctxt->error != NULL)
5488 ctxt->error(ctxt->userData,
5489 "Internal error: reference has content in CheckReference %s\n",
5490 name);
5491 ctxt->nbErrors++;
5492 return;
5493 }
5494 if (grammar->defs != NULL) {
5495 def = xmlHashLookup(grammar->defs, name);
5496 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005497 cur = ref;
5498 while (cur != NULL) {
5499 cur->content = def;
5500 cur = cur->nextHash;
5501 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005502 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005503 if (ctxt->error != NULL)
5504 ctxt->error(ctxt->userData,
5505 "Reference %s has no matching definition\n",
5506 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005507 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005508 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005509 } else {
5510 if (ctxt->error != NULL)
5511 ctxt->error(ctxt->userData,
5512 "Reference %s has no matching definition\n",
5513 name);
5514 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005515 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005516}
5517
5518/**
5519 * xmlRelaxNGCheckCombine:
5520 * @define: the define(s) list
5521 * @ctxt: a Relax-NG parser context
5522 * @name: the name associated to the defines
5523 *
5524 * Applies the 4.17. combine attribute rule for all the define
5525 * element of a given grammar using the same name.
5526 */
5527static void
5528xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5529 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5530 xmlChar *combine;
5531 int choiceOrInterleave = -1;
5532 int missing = 0;
5533 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5534
5535 if (define->nextHash == NULL)
5536 return;
5537 cur = define;
5538 while (cur != NULL) {
5539 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5540 if (combine != NULL) {
5541 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5542 if (choiceOrInterleave == -1)
5543 choiceOrInterleave = 1;
5544 else if (choiceOrInterleave == 0) {
5545 if (ctxt->error != NULL)
5546 ctxt->error(ctxt->userData,
5547 "Defines for %s use both 'choice' and 'interleave'\n",
5548 name);
5549 ctxt->nbErrors++;
5550 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005551 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005552 if (choiceOrInterleave == -1)
5553 choiceOrInterleave = 0;
5554 else if (choiceOrInterleave == 1) {
5555 if (ctxt->error != NULL)
5556 ctxt->error(ctxt->userData,
5557 "Defines for %s use both 'choice' and 'interleave'\n",
5558 name);
5559 ctxt->nbErrors++;
5560 }
5561 } else {
5562 if (ctxt->error != NULL)
5563 ctxt->error(ctxt->userData,
5564 "Defines for %s use unknown combine value '%s''\n",
5565 name, combine);
5566 ctxt->nbErrors++;
5567 }
5568 xmlFree(combine);
5569 } else {
5570 if (missing == 0)
5571 missing = 1;
5572 else {
5573 if (ctxt->error != NULL)
5574 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005575 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005576 name);
5577 ctxt->nbErrors++;
5578 }
5579 }
5580
5581 cur = cur->nextHash;
5582 }
5583#ifdef DEBUG
5584 xmlGenericError(xmlGenericErrorContext,
5585 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5586 name, choiceOrInterleave);
5587#endif
5588 if (choiceOrInterleave == -1)
5589 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005590 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005591 if (cur == NULL)
5592 return;
5593 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005594 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005595 else
5596 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005597 tmp = define;
5598 last = NULL;
5599 while (tmp != NULL) {
5600 if (tmp->content != NULL) {
5601 if (tmp->content->next != NULL) {
5602 /*
5603 * we need first to create a wrapper.
5604 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005605 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005606 if (tmp2 == NULL)
5607 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005608 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005609 tmp2->content = tmp->content;
5610 } else {
5611 tmp2 = tmp->content;
5612 }
5613 if (last == NULL) {
5614 cur->content = tmp2;
5615 } else {
5616 last->next = tmp2;
5617 }
5618 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005619 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005620 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005621 tmp = tmp->nextHash;
5622 }
5623 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005624 if (choiceOrInterleave == 0) {
5625 if (ctxt->interleaves == NULL)
5626 ctxt->interleaves = xmlHashCreate(10);
5627 if (ctxt->interleaves == NULL) {
5628 if (ctxt->error != NULL)
5629 ctxt->error(ctxt->userData,
5630 "Failed to create interleaves hash table\n");
5631 ctxt->nbErrors++;
5632 } else {
5633 char tmpname[32];
5634
5635 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5636 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5637 if (ctxt->error != NULL)
5638 ctxt->error(ctxt->userData,
5639 "Failed to add %s to hash table\n", tmpname);
5640 ctxt->nbErrors++;
5641 }
5642 }
5643 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005644}
5645
5646/**
5647 * xmlRelaxNGCombineStart:
5648 * @ctxt: a Relax-NG parser context
5649 * @grammar: the grammar
5650 *
5651 * Applies the 4.17. combine rule for all the start
5652 * element of a given grammar.
5653 */
5654static void
5655xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5656 xmlRelaxNGGrammarPtr grammar) {
5657 xmlRelaxNGDefinePtr starts;
5658 xmlChar *combine;
5659 int choiceOrInterleave = -1;
5660 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005661 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005662
Daniel Veillard2df2de22003-02-17 23:34:33 +00005663 starts = grammar->start;
5664 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005665 return;
5666 cur = starts;
5667 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005668 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5669 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5670 combine = NULL;
5671 if (ctxt->error != NULL)
5672 ctxt->error(ctxt->userData,
5673 "Internal error: start element not found\n");
5674 ctxt->nbErrors++;
5675 } else {
5676 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5677 }
5678
Daniel Veillard6eadf632003-01-23 18:29:16 +00005679 if (combine != NULL) {
5680 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5681 if (choiceOrInterleave == -1)
5682 choiceOrInterleave = 1;
5683 else if (choiceOrInterleave == 0) {
5684 if (ctxt->error != NULL)
5685 ctxt->error(ctxt->userData,
5686 "<start> use both 'choice' and 'interleave'\n");
5687 ctxt->nbErrors++;
5688 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005689 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005690 if (choiceOrInterleave == -1)
5691 choiceOrInterleave = 0;
5692 else if (choiceOrInterleave == 1) {
5693 if (ctxt->error != NULL)
5694 ctxt->error(ctxt->userData,
5695 "<start> use both 'choice' and 'interleave'\n");
5696 ctxt->nbErrors++;
5697 }
5698 } else {
5699 if (ctxt->error != NULL)
5700 ctxt->error(ctxt->userData,
5701 "<start> uses unknown combine value '%s''\n", combine);
5702 ctxt->nbErrors++;
5703 }
5704 xmlFree(combine);
5705 } else {
5706 if (missing == 0)
5707 missing = 1;
5708 else {
5709 if (ctxt->error != NULL)
5710 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005711 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005712 ctxt->nbErrors++;
5713 }
5714 }
5715
Daniel Veillard2df2de22003-02-17 23:34:33 +00005716 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005717 }
5718#ifdef DEBUG
5719 xmlGenericError(xmlGenericErrorContext,
5720 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5721 choiceOrInterleave);
5722#endif
5723 if (choiceOrInterleave == -1)
5724 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005725 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005726 if (cur == NULL)
5727 return;
5728 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005729 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005730 else
5731 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005732 cur->content = grammar->start;
5733 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005734 if (choiceOrInterleave == 0) {
5735 if (ctxt->interleaves == NULL)
5736 ctxt->interleaves = xmlHashCreate(10);
5737 if (ctxt->interleaves == NULL) {
5738 if (ctxt->error != NULL)
5739 ctxt->error(ctxt->userData,
5740 "Failed to create interleaves hash table\n");
5741 ctxt->nbErrors++;
5742 } else {
5743 char tmpname[32];
5744
5745 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5746 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5747 if (ctxt->error != NULL)
5748 ctxt->error(ctxt->userData,
5749 "Failed to add %s to hash table\n", tmpname);
5750 ctxt->nbErrors++;
5751 }
5752 }
5753 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005754}
5755
5756/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005757 * xmlRelaxNGCheckCycles:
5758 * @ctxt: a Relax-NG parser context
5759 * @nodes: grammar children nodes
5760 * @depth: the counter
5761 *
5762 * Check for cycles.
5763 *
5764 * Returns 0 if check passed, and -1 in case of error
5765 */
5766static int
5767xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5768 xmlRelaxNGDefinePtr cur, int depth) {
5769 int ret = 0;
5770
5771 while ((ret == 0) && (cur != NULL)) {
5772 if ((cur->type == XML_RELAXNG_REF) ||
5773 (cur->type == XML_RELAXNG_PARENTREF)) {
5774 if (cur->depth == -1) {
5775 cur->depth = depth;
5776 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5777 cur->depth = -2;
5778 } else if (depth == cur->depth) {
5779 if (ctxt->error != NULL)
5780 ctxt->error(ctxt->userData,
5781 "Detected a cycle in %s references\n", cur->name);
5782 ctxt->nbErrors++;
5783 return(-1);
5784 }
5785 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5786 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5787 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005788 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005789 }
5790 cur = cur->next;
5791 }
5792 return(ret);
5793}
5794
5795/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005796 * xmlRelaxNGTryUnlink:
5797 * @ctxt: a Relax-NG parser context
5798 * @cur: the definition to unlink
5799 * @parent: the parent definition
5800 * @prev: the previous sibling definition
5801 *
5802 * Try to unlink a definition. If not possble make it a NOOP
5803 *
5804 * Returns the new prev definition
5805 */
5806static xmlRelaxNGDefinePtr
5807xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5808 xmlRelaxNGDefinePtr cur,
5809 xmlRelaxNGDefinePtr parent,
5810 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005811 if (prev != NULL) {
5812 prev->next = cur->next;
5813 } else {
5814 if (parent != NULL) {
5815 if (parent->content == cur)
5816 parent->content = cur->next;
5817 else if (parent->attrs == cur)
5818 parent->attrs = cur->next;
5819 else if (parent->nameClass == cur)
5820 parent->nameClass = cur->next;
5821 } else {
5822 cur->type = XML_RELAXNG_NOOP;
5823 prev = cur;
5824 }
5825 }
5826 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005827}
5828
5829/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005830 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005831 * @ctxt: a Relax-NG parser context
5832 * @nodes: grammar children nodes
5833 *
5834 * Check for simplification of empty and notAllowed
5835 */
5836static void
5837xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5838 xmlRelaxNGDefinePtr cur,
5839 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005840 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005841
Daniel Veillardfd573f12003-03-16 17:52:32 +00005842 while (cur != NULL) {
5843 if ((cur->type == XML_RELAXNG_REF) ||
5844 (cur->type == XML_RELAXNG_PARENTREF)) {
5845 if (cur->depth != -3) {
5846 cur->depth = -3;
5847 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005848 }
5849 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005850 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005851 if ((parent != NULL) &&
5852 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5853 (parent->type == XML_RELAXNG_LIST) ||
5854 (parent->type == XML_RELAXNG_GROUP) ||
5855 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005856 (parent->type == XML_RELAXNG_ONEORMORE) ||
5857 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005858 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005859 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005860 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005861 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005862 (parent->type == XML_RELAXNG_CHOICE)) {
5863 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5864 } else
5865 prev = cur;
5866 } else if (cur->type == XML_RELAXNG_EMPTY){
5867 cur->parent = parent;
5868 if ((parent != NULL) &&
5869 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5870 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005871 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005872 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005873 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005874 if ((parent != NULL) &&
5875 ((parent->type == XML_RELAXNG_GROUP) ||
5876 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5877 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5878 } else
5879 prev = cur;
5880 } else {
5881 cur->parent = parent;
5882 if (cur->content != NULL)
5883 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005884 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005885 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5886 if (cur->nameClass != NULL)
5887 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5888 /*
Daniel Veillardce192eb2003-04-16 15:58:05 +00005889 * On Elements, try to move attribute only generating rules on
5890 * the attrs rules.
5891 */
5892 if (cur->type == XML_RELAXNG_ELEMENT) {
5893 int attronly;
5894 xmlRelaxNGDefinePtr tmp, pre;
5895
5896 while (cur->content != NULL) {
5897 attronly = xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5898 if (attronly == 1) {
5899 /*
5900 * migrate cur->content to attrs
5901 */
5902 tmp = cur->content;
5903 cur->content = tmp->next;
5904 tmp->next = cur->attrs;
5905 cur->attrs = tmp;
5906 } else {
5907 /*
5908 * cur->content can generate elements or text
5909 */
5910 break;
5911 }
5912 }
5913 pre = cur->content;
5914 while ((pre != NULL) && (pre->next != NULL)) {
5915 tmp = pre->next;
5916 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5917 if (attronly == 1) {
5918 /*
5919 * migrate tmp to attrs
5920 */
5921 pre->next = tmp->next;
5922 tmp->next = cur->attrs;
5923 cur->attrs = tmp;
5924 } else {
5925 pre = tmp;
5926 }
5927 }
5928 }
5929 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00005930 * This may result in a simplification
5931 */
5932 if ((cur->type == XML_RELAXNG_GROUP) ||
5933 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5934 if (cur->content == NULL)
5935 cur->type = XML_RELAXNG_EMPTY;
5936 else if (cur->content->next == NULL) {
5937 if ((parent == NULL) && (prev == NULL)) {
5938 cur->type = XML_RELAXNG_NOOP;
5939 } else if (prev == NULL) {
5940 parent->content = cur->content;
5941 cur->content->next = cur->next;
5942 cur = cur->content;
5943 } else {
5944 cur->content->next = cur->next;
5945 prev->next = cur->content;
5946 cur = cur->content;
5947 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005948 }
5949 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005950 /*
5951 * the current node may have been transformed back
5952 */
5953 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5954 (cur->content != NULL) &&
5955 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5956 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5957 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5958 if ((parent != NULL) &&
5959 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5960 (parent->type == XML_RELAXNG_LIST) ||
5961 (parent->type == XML_RELAXNG_GROUP) ||
5962 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5963 (parent->type == XML_RELAXNG_ONEORMORE) ||
5964 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5965 parent->type = XML_RELAXNG_NOT_ALLOWED;
5966 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005967 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005968 if ((parent != NULL) &&
5969 (parent->type == XML_RELAXNG_CHOICE)) {
5970 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5971 } else
5972 prev = cur;
5973 } else if (cur->type == XML_RELAXNG_EMPTY){
5974 if ((parent != NULL) &&
5975 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5976 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5977 parent->type = XML_RELAXNG_EMPTY;
5978 break;
5979 }
5980 if ((parent != NULL) &&
5981 ((parent->type == XML_RELAXNG_GROUP) ||
5982 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5983 (parent->type == XML_RELAXNG_CHOICE))) {
5984 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5985 } else
5986 prev = cur;
5987 } else {
5988 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005989 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005990 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005991 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005992 }
5993}
5994
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005995/**
5996 * xmlRelaxNGGroupContentType:
5997 * @ct1: the first content type
5998 * @ct2: the second content type
5999 *
6000 * Try to group 2 content types
6001 *
6002 * Returns the content type
6003 */
6004static xmlRelaxNGContentType
6005xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6006 xmlRelaxNGContentType ct2) {
6007 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6008 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6009 return(XML_RELAXNG_CONTENT_ERROR);
6010 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6011 return(ct2);
6012 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6013 return(ct1);
6014 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6015 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6016 return(XML_RELAXNG_CONTENT_COMPLEX);
6017 return(XML_RELAXNG_CONTENT_ERROR);
6018}
6019
6020/**
6021 * xmlRelaxNGMaxContentType:
6022 * @ct1: the first content type
6023 * @ct2: the second content type
6024 *
6025 * Compute the max content-type
6026 *
6027 * Returns the content type
6028 */
6029static xmlRelaxNGContentType
6030xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6031 xmlRelaxNGContentType ct2) {
6032 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6033 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6034 return(XML_RELAXNG_CONTENT_ERROR);
6035 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6036 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6037 return(XML_RELAXNG_CONTENT_SIMPLE);
6038 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6039 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6040 return(XML_RELAXNG_CONTENT_COMPLEX);
6041 return(XML_RELAXNG_CONTENT_EMPTY);
6042}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006043
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006044/**
6045 * xmlRelaxNGCheckRules:
6046 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006047 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006048 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006049 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006050 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006051 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006052 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006053 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006054 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006055static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00006056xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6057 xmlRelaxNGDefinePtr cur, int flags,
6058 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006059 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006060 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006061
Daniel Veillardfd573f12003-03-16 17:52:32 +00006062 while (cur != NULL) {
6063 ret = XML_RELAXNG_CONTENT_EMPTY;
6064 if ((cur->type == XML_RELAXNG_REF) ||
6065 (cur->type == XML_RELAXNG_PARENTREF)) {
6066 if (flags & XML_RELAXNG_IN_LIST) {
6067 if (ctxt->error != NULL)
6068 ctxt->error(ctxt->userData,
6069 "Found forbidden pattern list//ref\n");
6070 ctxt->nbErrors++;
6071 }
6072 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6073 if (ctxt->error != NULL)
6074 ctxt->error(ctxt->userData,
6075 "Found forbidden pattern data/except//ref\n");
6076 ctxt->nbErrors++;
6077 }
6078 if (cur->depth > -4) {
6079 cur->depth = -4;
6080 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6081 flags, cur->type);
6082 cur->depth = ret - 15 ;
6083 } else if (cur->depth == -4) {
6084 ret = XML_RELAXNG_CONTENT_COMPLEX;
6085 } else {
6086 ret = (xmlRelaxNGContentType) cur->depth + 15;
6087 }
6088 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6089 /*
6090 * The 7.3 Attribute derivation rule for groups is plugged there
6091 */
6092 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6093 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6094 if (ctxt->error != NULL)
6095 ctxt->error(ctxt->userData,
6096 "Found forbidden pattern data/except//element(ref)\n");
6097 ctxt->nbErrors++;
6098 }
6099 if (flags & XML_RELAXNG_IN_LIST) {
6100 if (ctxt->error != NULL)
6101 ctxt->error(ctxt->userData,
6102 "Found forbidden pattern list//element(ref)\n");
6103 ctxt->nbErrors++;
6104 }
6105 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6106 if (ctxt->error != NULL)
6107 ctxt->error(ctxt->userData,
6108 "Found forbidden pattern attribute//element(ref)\n");
6109 ctxt->nbErrors++;
6110 }
6111 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6112 if (ctxt->error != NULL)
6113 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00006114 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006115 ctxt->nbErrors++;
6116 }
6117 /*
6118 * reset since in the simple form elements are only child
6119 * of grammar/define
6120 */
6121 nflags = 0;
6122 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6123 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6124 if (ctxt->error != NULL)
6125 ctxt->error(ctxt->userData,
6126 "Element %s attributes have a content type error\n",
6127 cur->name);
6128 ctxt->nbErrors++;
6129 }
6130 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6131 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6132 if (ctxt->error != NULL)
6133 ctxt->error(ctxt->userData,
6134 "Element %s has a content type error\n",
6135 cur->name);
6136 ctxt->nbErrors++;
6137 } else {
6138 ret = XML_RELAXNG_CONTENT_COMPLEX;
6139 }
6140 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6141 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6142 if (ctxt->error != NULL)
6143 ctxt->error(ctxt->userData,
6144 "Found forbidden pattern attribute//attribute\n");
6145 ctxt->nbErrors++;
6146 }
6147 if (flags & XML_RELAXNG_IN_LIST) {
6148 if (ctxt->error != NULL)
6149 ctxt->error(ctxt->userData,
6150 "Found forbidden pattern list//attribute\n");
6151 ctxt->nbErrors++;
6152 }
6153 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6154 if (ctxt->error != NULL)
6155 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006156 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006157 ctxt->nbErrors++;
6158 }
6159 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6160 if (ctxt->error != NULL)
6161 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006162 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006163 ctxt->nbErrors++;
6164 }
6165 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6166 if (ctxt->error != NULL)
6167 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006168 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006169 ctxt->nbErrors++;
6170 }
6171 if (flags & XML_RELAXNG_IN_START) {
6172 if (ctxt->error != NULL)
6173 ctxt->error(ctxt->userData,
6174 "Found forbidden pattern start//attribute\n");
6175 ctxt->nbErrors++;
6176 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006177 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
6178 if (cur->ns == NULL) {
6179 if (ctxt->error != NULL)
6180 ctxt->error(ctxt->userData,
6181 "Found anyName attribute without oneOrMore ancestor\n");
6182 ctxt->nbErrors++;
6183 } else {
6184 if (ctxt->error != NULL)
6185 ctxt->error(ctxt->userData,
6186 "Found nsName attribute without oneOrMore ancestor\n");
6187 ctxt->nbErrors++;
6188 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00006189 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006190 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6191 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6192 ret = XML_RELAXNG_CONTENT_EMPTY;
6193 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6194 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6195 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6196 if (ctxt->error != NULL)
6197 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006198 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006199 ctxt->nbErrors++;
6200 }
6201 if (flags & XML_RELAXNG_IN_START) {
6202 if (ctxt->error != NULL)
6203 ctxt->error(ctxt->userData,
6204 "Found forbidden pattern start//oneOrMore\n");
6205 ctxt->nbErrors++;
6206 }
6207 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6208 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6209 ret = xmlRelaxNGGroupContentType(ret, ret);
6210 } else if (cur->type == XML_RELAXNG_LIST) {
6211 if (flags & XML_RELAXNG_IN_LIST) {
6212 if (ctxt->error != NULL)
6213 ctxt->error(ctxt->userData,
6214 "Found forbidden pattern list//list\n");
6215 ctxt->nbErrors++;
6216 }
6217 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6218 if (ctxt->error != NULL)
6219 ctxt->error(ctxt->userData,
6220 "Found forbidden pattern data/except//list\n");
6221 ctxt->nbErrors++;
6222 }
6223 if (flags & XML_RELAXNG_IN_START) {
6224 if (ctxt->error != NULL)
6225 ctxt->error(ctxt->userData,
6226 "Found forbidden pattern start//list\n");
6227 ctxt->nbErrors++;
6228 }
6229 nflags = flags | XML_RELAXNG_IN_LIST;
6230 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6231 } else if (cur->type == XML_RELAXNG_GROUP) {
6232 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6233 if (ctxt->error != NULL)
6234 ctxt->error(ctxt->userData,
6235 "Found forbidden pattern data/except//group\n");
6236 ctxt->nbErrors++;
6237 }
6238 if (flags & XML_RELAXNG_IN_START) {
6239 if (ctxt->error != NULL)
6240 ctxt->error(ctxt->userData,
6241 "Found forbidden pattern start//group\n");
6242 ctxt->nbErrors++;
6243 }
6244 if (flags & XML_RELAXNG_IN_ONEORMORE)
6245 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6246 else
6247 nflags = flags;
6248 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6249 /*
6250 * The 7.3 Attribute derivation rule for groups is plugged there
6251 */
6252 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6253 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6254 if (flags & XML_RELAXNG_IN_LIST) {
6255 if (ctxt->error != NULL)
6256 ctxt->error(ctxt->userData,
6257 "Found forbidden pattern list//interleave\n");
6258 ctxt->nbErrors++;
6259 }
6260 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6261 if (ctxt->error != NULL)
6262 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006263 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006264 ctxt->nbErrors++;
6265 }
6266 if (flags & XML_RELAXNG_IN_START) {
6267 if (ctxt->error != NULL)
6268 ctxt->error(ctxt->userData,
6269 "Found forbidden pattern start//interleave\n");
6270 ctxt->nbErrors++;
6271 }
6272 if (flags & XML_RELAXNG_IN_ONEORMORE)
6273 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6274 else
6275 nflags = flags;
6276 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6277 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6278 if ((cur->parent != NULL) &&
6279 (cur->parent->type == XML_RELAXNG_DATATYPE))
6280 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6281 else
6282 nflags = flags;
6283 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6284 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6285 if (flags & XML_RELAXNG_IN_START) {
6286 if (ctxt->error != NULL)
6287 ctxt->error(ctxt->userData,
6288 "Found forbidden pattern start//data\n");
6289 ctxt->nbErrors++;
6290 }
6291 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6292 ret = XML_RELAXNG_CONTENT_SIMPLE;
6293 } else if (cur->type == XML_RELAXNG_VALUE) {
6294 if (flags & XML_RELAXNG_IN_START) {
6295 if (ctxt->error != NULL)
6296 ctxt->error(ctxt->userData,
6297 "Found forbidden pattern start//value\n");
6298 ctxt->nbErrors++;
6299 }
6300 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6301 ret = XML_RELAXNG_CONTENT_SIMPLE;
6302 } else if (cur->type == XML_RELAXNG_TEXT) {
6303 if (flags & XML_RELAXNG_IN_LIST) {
6304 if (ctxt->error != NULL)
6305 ctxt->error(ctxt->userData,
6306 "Found forbidden pattern list//text\n");
6307 ctxt->nbErrors++;
6308 }
6309 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6310 if (ctxt->error != NULL)
6311 ctxt->error(ctxt->userData,
6312 "Found forbidden pattern data/except//text\n");
6313 ctxt->nbErrors++;
6314 }
6315 if (flags & XML_RELAXNG_IN_START) {
6316 if (ctxt->error != NULL)
6317 ctxt->error(ctxt->userData,
6318 "Found forbidden pattern start//text\n");
6319 ctxt->nbErrors++;
6320 }
6321 ret = XML_RELAXNG_CONTENT_COMPLEX;
6322 } else if (cur->type == XML_RELAXNG_EMPTY) {
6323 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6324 if (ctxt->error != NULL)
6325 ctxt->error(ctxt->userData,
6326 "Found forbidden pattern data/except//empty\n");
6327 ctxt->nbErrors++;
6328 }
6329 if (flags & XML_RELAXNG_IN_START) {
6330 if (ctxt->error != NULL)
6331 ctxt->error(ctxt->userData,
6332 "Found forbidden pattern start//empty\n");
6333 ctxt->nbErrors++;
6334 }
6335 ret = XML_RELAXNG_CONTENT_EMPTY;
6336 } else if (cur->type == XML_RELAXNG_CHOICE) {
6337 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6338 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6339 } else {
6340 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6341 }
6342 cur = cur->next;
6343 if (ptype == XML_RELAXNG_GROUP) {
6344 val = xmlRelaxNGGroupContentType(val, ret);
6345 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6346 tmp = xmlRelaxNGGroupContentType(val, ret);
6347 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6348 tmp = xmlRelaxNGMaxContentType(val, ret);
6349 } else if (ptype == XML_RELAXNG_CHOICE) {
6350 val = xmlRelaxNGMaxContentType(val, ret);
6351 } else if (ptype == XML_RELAXNG_LIST) {
6352 val = XML_RELAXNG_CONTENT_SIMPLE;
6353 } else if (ptype == XML_RELAXNG_EXCEPT) {
6354 if (ret == XML_RELAXNG_CONTENT_ERROR)
6355 val = XML_RELAXNG_CONTENT_ERROR;
6356 else
6357 val = XML_RELAXNG_CONTENT_SIMPLE;
6358 } else {
6359 val = xmlRelaxNGGroupContentType(val, ret);
6360 }
6361
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006362 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006363 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006364}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006365
6366/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006367 * xmlRelaxNGParseGrammar:
6368 * @ctxt: a Relax-NG parser context
6369 * @nodes: grammar children nodes
6370 *
6371 * parse a Relax-NG <grammar> node
6372 *
6373 * Returns the internal xmlRelaxNGGrammarPtr built or
6374 * NULL in case of error
6375 */
6376static xmlRelaxNGGrammarPtr
6377xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6378 xmlRelaxNGGrammarPtr ret, tmp, old;
6379
Daniel Veillardc482e262003-02-26 14:48:48 +00006380#ifdef DEBUG_GRAMMAR
6381 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6382#endif
6383
Daniel Veillard6eadf632003-01-23 18:29:16 +00006384 ret = xmlRelaxNGNewGrammar(ctxt);
6385 if (ret == NULL)
6386 return(NULL);
6387
6388 /*
6389 * Link the new grammar in the tree
6390 */
6391 ret->parent = ctxt->grammar;
6392 if (ctxt->grammar != NULL) {
6393 tmp = ctxt->grammar->children;
6394 if (tmp == NULL) {
6395 ctxt->grammar->children = ret;
6396 } else {
6397 while (tmp->next != NULL)
6398 tmp = tmp->next;
6399 tmp->next = ret;
6400 }
6401 }
6402
6403 old = ctxt->grammar;
6404 ctxt->grammar = ret;
6405 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6406 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006407 if (ctxt->grammar == NULL) {
6408 if (ctxt->error != NULL)
6409 ctxt->error(ctxt->userData,
6410 "Failed to parse <grammar> content\n");
6411 ctxt->nbErrors++;
6412 } else if (ctxt->grammar->start == NULL) {
6413 if (ctxt->error != NULL)
6414 ctxt->error(ctxt->userData,
6415 "Element <grammar> has no <start>\n");
6416 ctxt->nbErrors++;
6417 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006418
6419 /*
6420 * Apply 4.17 mergingd rules to defines and starts
6421 */
6422 xmlRelaxNGCombineStart(ctxt, ret);
6423 if (ret->defs != NULL) {
6424 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6425 ctxt);
6426 }
6427
6428 /*
6429 * link together defines and refs in this grammar
6430 */
6431 if (ret->refs != NULL) {
6432 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6433 ctxt);
6434 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006435
Daniel Veillard6eadf632003-01-23 18:29:16 +00006436 ctxt->grammar = old;
6437 return(ret);
6438}
6439
6440/**
6441 * xmlRelaxNGParseDocument:
6442 * @ctxt: a Relax-NG parser context
6443 * @node: the root node of the RelaxNG schema
6444 *
6445 * parse a Relax-NG definition resource and build an internal
6446 * xmlRelaxNG struture which can be used to validate instances.
6447 *
6448 * Returns the internal XML RelaxNG structure built or
6449 * NULL in case of error
6450 */
6451static xmlRelaxNGPtr
6452xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6453 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006454 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006455 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006456
6457 if ((ctxt == NULL) || (node == NULL))
6458 return (NULL);
6459
6460 schema = xmlRelaxNGNewRelaxNG(ctxt);
6461 if (schema == NULL)
6462 return(NULL);
6463
Daniel Veillard276be4a2003-01-24 01:03:34 +00006464 olddefine = ctxt->define;
6465 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006466 if (IS_RELAXNG(node, "grammar")) {
6467 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6468 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00006469 xmlRelaxNGGrammarPtr tmp, ret;
6470
6471 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006472 if (schema->topgrammar == NULL) {
6473 return(schema);
6474 }
Daniel Veillardc482e262003-02-26 14:48:48 +00006475 /*
6476 * Link the new grammar in the tree
6477 */
6478 ret->parent = ctxt->grammar;
6479 if (ctxt->grammar != NULL) {
6480 tmp = ctxt->grammar->children;
6481 if (tmp == NULL) {
6482 ctxt->grammar->children = ret;
6483 } else {
6484 while (tmp->next != NULL)
6485 tmp = tmp->next;
6486 tmp->next = ret;
6487 }
6488 }
Daniel Veillarde431a272003-01-29 23:02:33 +00006489 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00006490 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006491 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00006492 if (old != NULL)
6493 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006494 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006495 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006496 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006497 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006498 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006499 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6500 while ((schema->topgrammar->start != NULL) &&
6501 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6502 (schema->topgrammar->start->next != NULL))
6503 schema->topgrammar->start = schema->topgrammar->start->content;
6504 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6505 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006506 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006507 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006508
6509#ifdef DEBUG
6510 if (schema == NULL)
6511 xmlGenericError(xmlGenericErrorContext,
6512 "xmlRelaxNGParseDocument() failed\n");
6513#endif
6514
6515 return (schema);
6516}
6517
6518/************************************************************************
6519 * *
6520 * Reading RelaxNGs *
6521 * *
6522 ************************************************************************/
6523
6524/**
6525 * xmlRelaxNGNewParserCtxt:
6526 * @URL: the location of the schema
6527 *
6528 * Create an XML RelaxNGs parse context for that file/resource expected
6529 * to contain an XML RelaxNGs file.
6530 *
6531 * Returns the parser context or NULL in case of error
6532 */
6533xmlRelaxNGParserCtxtPtr
6534xmlRelaxNGNewParserCtxt(const char *URL) {
6535 xmlRelaxNGParserCtxtPtr ret;
6536
6537 if (URL == NULL)
6538 return(NULL);
6539
6540 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6541 if (ret == NULL) {
6542 xmlGenericError(xmlGenericErrorContext,
6543 "Failed to allocate new schama parser context for %s\n", URL);
6544 return (NULL);
6545 }
6546 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6547 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006548 ret->error = xmlGenericError;
6549 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006550 return (ret);
6551}
6552
6553/**
6554 * xmlRelaxNGNewMemParserCtxt:
6555 * @buffer: a pointer to a char array containing the schemas
6556 * @size: the size of the array
6557 *
6558 * Create an XML RelaxNGs parse context for that memory buffer expected
6559 * to contain an XML RelaxNGs file.
6560 *
6561 * Returns the parser context or NULL in case of error
6562 */
6563xmlRelaxNGParserCtxtPtr
6564xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6565 xmlRelaxNGParserCtxtPtr ret;
6566
6567 if ((buffer == NULL) || (size <= 0))
6568 return(NULL);
6569
6570 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6571 if (ret == NULL) {
6572 xmlGenericError(xmlGenericErrorContext,
6573 "Failed to allocate new schama parser context\n");
6574 return (NULL);
6575 }
6576 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6577 ret->buffer = buffer;
6578 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006579 ret->error = xmlGenericError;
6580 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006581 return (ret);
6582}
6583
6584/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006585 * xmlRelaxNGNewDocParserCtxt:
6586 * @doc: a preparsed document tree
6587 *
6588 * Create an XML RelaxNGs parser context for that document.
6589 * Note: since the process of compiling a RelaxNG schemas modifies the
6590 * document, the @doc parameter is duplicated internally.
6591 *
6592 * Returns the parser context or NULL in case of error
6593 */
6594xmlRelaxNGParserCtxtPtr
6595xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) {
6596 xmlRelaxNGParserCtxtPtr ret;
6597 xmlDocPtr copy;
6598
6599 if (doc == NULL)
6600 return(NULL);
6601 copy = xmlCopyDoc(doc, 1);
6602 if (copy == NULL)
6603 return(NULL);
6604
6605 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6606 if (ret == NULL) {
6607 xmlGenericError(xmlGenericErrorContext,
6608 "Failed to allocate new schama parser context\n");
6609 return (NULL);
6610 }
6611 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6612 ret->document = copy;
6613 ret->userData = xmlGenericErrorContext;
6614 return (ret);
6615}
6616
6617/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006618 * xmlRelaxNGFreeParserCtxt:
6619 * @ctxt: the schema parser context
6620 *
6621 * Free the resources associated to the schema parser context
6622 */
6623void
6624xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6625 if (ctxt == NULL)
6626 return;
6627 if (ctxt->URL != NULL)
6628 xmlFree(ctxt->URL);
6629 if (ctxt->doc != NULL)
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00006630 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006631 if (ctxt->interleaves != NULL)
6632 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006633 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006634 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006635 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006636 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006637 if (ctxt->docTab != NULL)
6638 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006639 if (ctxt->incTab != NULL)
6640 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006641 if (ctxt->defTab != NULL) {
6642 int i;
6643
6644 for (i = 0;i < ctxt->defNr;i++)
6645 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6646 xmlFree(ctxt->defTab);
6647 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006648 xmlFree(ctxt);
6649}
6650
Daniel Veillard6eadf632003-01-23 18:29:16 +00006651/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006652 * xmlRelaxNGNormExtSpace:
6653 * @value: a value
6654 *
6655 * Removes the leading and ending spaces of the value
6656 * The string is modified "in situ"
6657 */
6658static void
6659xmlRelaxNGNormExtSpace(xmlChar *value) {
6660 xmlChar *start = value;
6661 xmlChar *cur = value;
6662 if (value == NULL)
6663 return;
6664
6665 while (IS_BLANK(*cur)) cur++;
6666 if (cur == start) {
6667 do {
6668 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6669 if (*cur == 0)
6670 return;
6671 start = cur;
6672 while (IS_BLANK(*cur)) cur++;
6673 if (*cur == 0) {
6674 *start = 0;
6675 return;
6676 }
6677 } while (1);
6678 } else {
6679 do {
6680 while ((*cur != 0) && (!IS_BLANK(*cur)))
6681 *start++ = *cur++;
6682 if (*cur == 0) {
6683 *start = 0;
6684 return;
6685 }
6686 /* don't try to normalize the inner spaces */
6687 while (IS_BLANK(*cur)) cur++;
6688 *start++ = *cur++;
6689 if (*cur == 0) {
6690 *start = 0;
6691 return;
6692 }
6693 } while (1);
6694 }
6695}
6696
6697/**
6698 * xmlRelaxNGCheckAttributes:
6699 * @ctxt: a Relax-NG parser context
6700 * @node: a Relax-NG node
6701 *
6702 * Check all the attributes on the given node
6703 */
6704static void
6705xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6706 xmlAttrPtr cur, next;
6707
6708 cur = node->properties;
6709 while (cur != NULL) {
6710 next = cur->next;
6711 if ((cur->ns == NULL) ||
6712 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6713 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6714 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6715 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6716 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6717 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006718 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006719 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6720 if (ctxt->error != NULL)
6721 ctxt->error(ctxt->userData,
6722 "Attribute %s is not allowed on %s\n",
6723 cur->name, node->name);
6724 ctxt->nbErrors++;
6725 }
6726 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6727 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6728 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6729 if (ctxt->error != NULL)
6730 ctxt->error(ctxt->userData,
6731 "Attribute %s is not allowed on %s\n",
6732 cur->name, node->name);
6733 ctxt->nbErrors++;
6734 }
6735 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6736 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6737 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6738 if (ctxt->error != NULL)
6739 ctxt->error(ctxt->userData,
6740 "Attribute %s is not allowed on %s\n",
6741 cur->name, node->name);
6742 ctxt->nbErrors++;
6743 }
6744 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6745 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6746 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6747 if (ctxt->error != NULL)
6748 ctxt->error(ctxt->userData,
6749 "Attribute %s is not allowed on %s\n",
6750 cur->name, node->name);
6751 ctxt->nbErrors++;
6752 }
6753 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6754 xmlChar *val;
6755 xmlURIPtr uri;
6756
6757 val = xmlNodeListGetString(node->doc, cur->children, 1);
6758 if (val != NULL) {
6759 if (val[0] != 0) {
6760 uri = xmlParseURI((const char *) val);
6761 if (uri == NULL) {
6762 if (ctxt->error != NULL)
6763 ctxt->error(ctxt->userData,
6764 "Attribute %s contains invalid URI %s\n",
6765 cur->name, val);
6766 ctxt->nbErrors++;
6767 } else {
6768 if (uri->scheme == NULL) {
6769 if (ctxt->error != NULL)
6770 ctxt->error(ctxt->userData,
6771 "Attribute %s URI %s is not absolute\n",
6772 cur->name, val);
6773 ctxt->nbErrors++;
6774 }
6775 if (uri->fragment != NULL) {
6776 if (ctxt->error != NULL)
6777 ctxt->error(ctxt->userData,
6778 "Attribute %s URI %s has a fragment ID\n",
6779 cur->name, val);
6780 ctxt->nbErrors++;
6781 }
6782 xmlFreeURI(uri);
6783 }
6784 }
6785 xmlFree(val);
6786 }
6787 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6788 if (ctxt->error != NULL)
6789 ctxt->error(ctxt->userData,
6790 "Unknown attribute %s on %s\n",
6791 cur->name, node->name);
6792 ctxt->nbErrors++;
6793 }
6794 }
6795 cur = next;
6796 }
6797}
6798
6799/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006800 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006801 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006802 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006803 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006804 * Cleanup the subtree from unwanted nodes for parsing, resolve
6805 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006806 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006807static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006808xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006809 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006810
Daniel Veillard6eadf632003-01-23 18:29:16 +00006811 delete = NULL;
6812 cur = root;
6813 while (cur != NULL) {
6814 if (delete != NULL) {
6815 xmlUnlinkNode(delete);
6816 xmlFreeNode(delete);
6817 delete = NULL;
6818 }
6819 if (cur->type == XML_ELEMENT_NODE) {
6820 /*
6821 * Simplification 4.1. Annotations
6822 */
6823 if ((cur->ns == NULL) ||
6824 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006825 if ((cur->parent != NULL) &&
6826 (cur->parent->type == XML_ELEMENT_NODE) &&
6827 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6828 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6829 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6830 if (ctxt->error != NULL)
6831 ctxt->error(ctxt->userData,
6832 "element %s doesn't allow foreign elements\n",
6833 cur->parent->name);
6834 ctxt->nbErrors++;
6835 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006836 delete = cur;
6837 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006838 } else {
6839 xmlRelaxNGCleanupAttributes(ctxt, cur);
6840 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6841 xmlChar *href, *ns, *base, *URL;
6842 xmlRelaxNGDocumentPtr docu;
6843 xmlNodePtr tmp;
6844
6845 ns = xmlGetProp(cur, BAD_CAST "ns");
6846 if (ns == NULL) {
6847 tmp = cur->parent;
6848 while ((tmp != NULL) &&
6849 (tmp->type == XML_ELEMENT_NODE)) {
6850 ns = xmlGetProp(tmp, BAD_CAST "ns");
6851 if (ns != NULL)
6852 break;
6853 tmp = tmp->parent;
6854 }
6855 }
6856 href = xmlGetProp(cur, BAD_CAST "href");
6857 if (href == NULL) {
6858 if (ctxt->error != NULL)
6859 ctxt->error(ctxt->userData,
6860 "xmlRelaxNGParse: externalRef has no href attribute\n");
6861 ctxt->nbErrors++;
6862 delete = cur;
6863 goto skip_children;
6864 }
6865 base = xmlNodeGetBase(cur->doc, cur);
6866 URL = xmlBuildURI(href, base);
6867 if (URL == NULL) {
6868 if (ctxt->error != NULL)
6869 ctxt->error(ctxt->userData,
6870 "Failed to compute URL for externalRef %s\n", href);
6871 ctxt->nbErrors++;
6872 if (href != NULL)
6873 xmlFree(href);
6874 if (base != NULL)
6875 xmlFree(base);
6876 delete = cur;
6877 goto skip_children;
6878 }
6879 if (href != NULL)
6880 xmlFree(href);
6881 if (base != NULL)
6882 xmlFree(base);
6883 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6884 if (docu == NULL) {
6885 if (ctxt->error != NULL)
6886 ctxt->error(ctxt->userData,
6887 "Failed to load externalRef %s\n", URL);
6888 ctxt->nbErrors++;
6889 xmlFree(URL);
6890 delete = cur;
6891 goto skip_children;
6892 }
6893 if (ns != NULL)
6894 xmlFree(ns);
6895 xmlFree(URL);
6896 cur->_private = docu;
6897 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6898 xmlChar *href, *ns, *base, *URL;
6899 xmlRelaxNGIncludePtr incl;
6900 xmlNodePtr tmp;
6901
6902 href = xmlGetProp(cur, BAD_CAST "href");
6903 if (href == NULL) {
6904 if (ctxt->error != NULL)
6905 ctxt->error(ctxt->userData,
6906 "xmlRelaxNGParse: include has no href attribute\n");
6907 ctxt->nbErrors++;
6908 delete = cur;
6909 goto skip_children;
6910 }
6911 base = xmlNodeGetBase(cur->doc, cur);
6912 URL = xmlBuildURI(href, base);
6913 if (URL == NULL) {
6914 if (ctxt->error != NULL)
6915 ctxt->error(ctxt->userData,
6916 "Failed to compute URL for include %s\n", href);
6917 ctxt->nbErrors++;
6918 if (href != NULL)
6919 xmlFree(href);
6920 if (base != NULL)
6921 xmlFree(base);
6922 delete = cur;
6923 goto skip_children;
6924 }
6925 if (href != NULL)
6926 xmlFree(href);
6927 if (base != NULL)
6928 xmlFree(base);
6929 ns = xmlGetProp(cur, BAD_CAST "ns");
6930 if (ns == NULL) {
6931 tmp = cur->parent;
6932 while ((tmp != NULL) &&
6933 (tmp->type == XML_ELEMENT_NODE)) {
6934 ns = xmlGetProp(tmp, BAD_CAST "ns");
6935 if (ns != NULL)
6936 break;
6937 tmp = tmp->parent;
6938 }
6939 }
6940 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6941 if (ns != NULL)
6942 xmlFree(ns);
6943 if (incl == NULL) {
6944 if (ctxt->error != NULL)
6945 ctxt->error(ctxt->userData,
6946 "Failed to load include %s\n", URL);
6947 ctxt->nbErrors++;
6948 xmlFree(URL);
6949 delete = cur;
6950 goto skip_children;
6951 }
6952 xmlFree(URL);
6953 cur->_private = incl;
6954 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6955 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6956 xmlChar *name, *ns;
6957 xmlNodePtr text = NULL;
6958
6959 /*
6960 * Simplification 4.8. name attribute of element
6961 * and attribute elements
6962 */
6963 name = xmlGetProp(cur, BAD_CAST "name");
6964 if (name != NULL) {
6965 if (cur->children == NULL) {
6966 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6967 name);
6968 } else {
6969 xmlNodePtr node;
6970 node = xmlNewNode(cur->ns, BAD_CAST "name");
6971 if (node != NULL) {
6972 xmlAddPrevSibling(cur->children, node);
6973 text = xmlNewText(name);
6974 xmlAddChild(node, text);
6975 text = node;
6976 }
6977 }
6978 if (text == NULL) {
6979 if (ctxt->error != NULL)
6980 ctxt->error(ctxt->userData,
6981 "Failed to create a name %s element\n", name);
6982 ctxt->nbErrors++;
6983 }
6984 xmlUnsetProp(cur, BAD_CAST "name");
6985 xmlFree(name);
6986 ns = xmlGetProp(cur, BAD_CAST "ns");
6987 if (ns != NULL) {
6988 if (text != NULL) {
6989 xmlSetProp(text, BAD_CAST "ns", ns);
6990 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6991 }
6992 xmlFree(ns);
6993 } else if (xmlStrEqual(cur->name,
6994 BAD_CAST "attribute")) {
6995 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6996 }
6997 }
6998 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6999 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7000 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7001 /*
7002 * Simplification 4.8. name attribute of element
7003 * and attribute elements
7004 */
7005 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7006 xmlNodePtr node;
7007 xmlChar *ns = NULL;
7008
7009 node = cur->parent;
7010 while ((node != NULL) &&
7011 (node->type == XML_ELEMENT_NODE)) {
7012 ns = xmlGetProp(node, BAD_CAST "ns");
7013 if (ns != NULL) {
7014 break;
7015 }
7016 node = node->parent;
7017 }
7018 if (ns == NULL) {
7019 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7020 } else {
7021 xmlSetProp(cur, BAD_CAST "ns", ns);
7022 xmlFree(ns);
7023 }
7024 }
7025 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7026 xmlChar *name, *local, *prefix;
7027
7028 /*
7029 * Simplification: 4.10. QNames
7030 */
7031 name = xmlNodeGetContent(cur);
7032 if (name != NULL) {
7033 local = xmlSplitQName2(name, &prefix);
7034 if (local != NULL) {
7035 xmlNsPtr ns;
7036
7037 ns = xmlSearchNs(cur->doc, cur, prefix);
7038 if (ns == NULL) {
7039 if (ctxt->error != NULL)
7040 ctxt->error(ctxt->userData,
7041 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
7042 ctxt->nbErrors++;
7043 } else {
7044 xmlSetProp(cur, BAD_CAST "ns", ns->href);
7045 xmlNodeSetContent(cur, local);
7046 }
7047 xmlFree(local);
7048 xmlFree(prefix);
7049 }
7050 xmlFree(name);
7051 }
7052 }
7053 /*
7054 * 4.16
7055 */
7056 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7057 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7058 if (ctxt->error != NULL)
7059 ctxt->error(ctxt->userData,
7060 "Found nsName/except//nsName forbidden construct\n");
7061 ctxt->nbErrors++;
7062 }
7063 }
7064 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7065 (cur != root)) {
7066 int oldflags = ctxt->flags;
7067
7068 /*
7069 * 4.16
7070 */
7071 if ((cur->parent != NULL) &&
7072 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
7073 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7074 xmlRelaxNGCleanupTree(ctxt, cur);
7075 ctxt->flags = oldflags;
7076 goto skip_children;
7077 } else if ((cur->parent != NULL) &&
7078 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
7079 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7080 xmlRelaxNGCleanupTree(ctxt, cur);
7081 ctxt->flags = oldflags;
7082 goto skip_children;
7083 }
7084 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7085 /*
7086 * 4.16
7087 */
7088 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7089 if (ctxt->error != NULL)
7090 ctxt->error(ctxt->userData,
7091 "Found anyName/except//anyName forbidden construct\n");
7092 ctxt->nbErrors++;
7093 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7094 if (ctxt->error != NULL)
7095 ctxt->error(ctxt->userData,
7096 "Found nsName/except//anyName forbidden construct\n");
7097 ctxt->nbErrors++;
7098 }
7099 }
7100 /*
7101 * Thisd is not an else since "include" is transformed
7102 * into a div
7103 */
7104 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7105 xmlChar *ns;
7106 xmlNodePtr child, ins, tmp;
7107
7108 /*
7109 * implements rule 4.11
7110 */
7111
7112 ns = xmlGetProp(cur, BAD_CAST "ns");
7113
7114 child = cur->children;
7115 ins = cur;
7116 while (child != NULL) {
7117 if (ns != NULL) {
7118 if (!xmlHasProp(child, BAD_CAST "ns")) {
7119 xmlSetProp(child, BAD_CAST "ns", ns);
7120 }
7121 }
7122 tmp = child->next;
7123 xmlUnlinkNode(child);
7124 ins = xmlAddNextSibling(ins, child);
7125 child = tmp;
7126 }
7127 if (ns != NULL)
7128 xmlFree(ns);
7129 delete = cur;
7130 goto skip_children;
7131 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007132 }
7133 }
7134 /*
7135 * Simplification 4.2 whitespaces
7136 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007137 else if ((cur->type == XML_TEXT_NODE) ||
7138 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007139 if (IS_BLANK_NODE(cur)) {
7140 if (cur->parent->type == XML_ELEMENT_NODE) {
7141 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
7142 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
7143 delete = cur;
7144 } else {
7145 delete = cur;
7146 goto skip_children;
7147 }
7148 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007149 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007150 delete = cur;
7151 goto skip_children;
7152 }
7153
7154 /*
7155 * Skip to next node
7156 */
7157 if (cur->children != NULL) {
7158 if ((cur->children->type != XML_ENTITY_DECL) &&
7159 (cur->children->type != XML_ENTITY_REF_NODE) &&
7160 (cur->children->type != XML_ENTITY_NODE)) {
7161 cur = cur->children;
7162 continue;
7163 }
7164 }
7165skip_children:
7166 if (cur->next != NULL) {
7167 cur = cur->next;
7168 continue;
7169 }
7170
7171 do {
7172 cur = cur->parent;
7173 if (cur == NULL)
7174 break;
7175 if (cur == root) {
7176 cur = NULL;
7177 break;
7178 }
7179 if (cur->next != NULL) {
7180 cur = cur->next;
7181 break;
7182 }
7183 } while (cur != NULL);
7184 }
7185 if (delete != NULL) {
7186 xmlUnlinkNode(delete);
7187 xmlFreeNode(delete);
7188 delete = NULL;
7189 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007190}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007191
Daniel Veillardc5312d72003-02-21 17:14:10 +00007192/**
7193 * xmlRelaxNGCleanupDoc:
7194 * @ctxt: a Relax-NG parser context
7195 * @doc: an xmldocPtr document pointer
7196 *
7197 * Cleanup the document from unwanted nodes for parsing, resolve
7198 * Include and externalRef lookups.
7199 *
7200 * Returns the cleaned up document or NULL in case of error
7201 */
7202static xmlDocPtr
7203xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
7204 xmlNodePtr root;
7205
7206 /*
7207 * Extract the root
7208 */
7209 root = xmlDocGetRootElement(doc);
7210 if (root == NULL) {
7211 if (ctxt->error != NULL)
7212 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7213 ctxt->URL);
7214 ctxt->nbErrors++;
7215 return (NULL);
7216 }
7217 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007218 return(doc);
7219}
7220
7221/**
7222 * xmlRelaxNGParse:
7223 * @ctxt: a Relax-NG parser context
7224 *
7225 * parse a schema definition resource and build an internal
7226 * XML Shema struture which can be used to validate instances.
7227 * *WARNING* this interface is highly subject to change
7228 *
7229 * Returns the internal XML RelaxNG structure built from the resource or
7230 * NULL in case of error
7231 */
7232xmlRelaxNGPtr
7233xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7234{
7235 xmlRelaxNGPtr ret = NULL;
7236 xmlDocPtr doc;
7237 xmlNodePtr root;
7238
7239 xmlRelaxNGInitTypes();
7240
7241 if (ctxt == NULL)
7242 return (NULL);
7243
7244 /*
7245 * First step is to parse the input document into an DOM/Infoset
7246 */
7247 if (ctxt->URL != NULL) {
7248 doc = xmlParseFile((const char *) ctxt->URL);
7249 if (doc == NULL) {
7250 if (ctxt->error != NULL)
7251 ctxt->error(ctxt->userData,
7252 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7253 ctxt->nbErrors++;
7254 return (NULL);
7255 }
7256 } else if (ctxt->buffer != NULL) {
7257 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7258 if (doc == NULL) {
7259 if (ctxt->error != NULL)
7260 ctxt->error(ctxt->userData,
7261 "xmlRelaxNGParse: could not parse schemas\n");
7262 ctxt->nbErrors++;
7263 return (NULL);
7264 }
7265 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7266 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007267 } else if (ctxt->document != NULL) {
7268 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007269 } else {
7270 if (ctxt->error != NULL)
7271 ctxt->error(ctxt->userData,
7272 "xmlRelaxNGParse: nothing to parse\n");
7273 ctxt->nbErrors++;
7274 return (NULL);
7275 }
7276 ctxt->document = doc;
7277
7278 /*
7279 * Some preprocessing of the document content
7280 */
7281 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7282 if (doc == NULL) {
7283 xmlFreeDoc(ctxt->document);
7284 ctxt->document = NULL;
7285 return(NULL);
7286 }
7287
Daniel Veillard6eadf632003-01-23 18:29:16 +00007288 /*
7289 * Then do the parsing for good
7290 */
7291 root = xmlDocGetRootElement(doc);
7292 if (root == NULL) {
7293 if (ctxt->error != NULL)
7294 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7295 ctxt->URL);
7296 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007297 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007298 return (NULL);
7299 }
7300 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007301 if (ret == NULL) {
7302 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007303 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007304 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007305
7306 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007307 * Check the ref/defines links
7308 */
7309 /*
7310 * try to preprocess interleaves
7311 */
7312 if (ctxt->interleaves != NULL) {
7313 xmlHashScan(ctxt->interleaves,
7314 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7315 }
7316
7317 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007318 * if there was a parsing error return NULL
7319 */
7320 if (ctxt->nbErrors > 0) {
7321 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007322 ctxt->document = NULL;
7323 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007324 return(NULL);
7325 }
7326
7327 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007328 * try to compile (parts of) the schemas
7329 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007330 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7331 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00007332 xmlRelaxNGDefinePtr def;
7333
7334 def = xmlRelaxNGNewDefine(ctxt, NULL);
7335 if (def != NULL) {
7336 def->type = XML_RELAXNG_START;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007337 def->content = ret->topgrammar->start;
7338 ret->topgrammar->start = def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007339 }
7340 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007341 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007342 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007343
7344 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007345 * Transfer the pointer for cleanup at the schema level.
7346 */
7347 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007348 ctxt->document = NULL;
7349 ret->documents = ctxt->documents;
7350 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007351
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007352 ret->includes = ctxt->includes;
7353 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007354 ret->defNr = ctxt->defNr;
7355 ret->defTab = ctxt->defTab;
7356 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007357 if (ctxt->idref == 1)
7358 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007359
7360 return (ret);
7361}
7362
7363/**
7364 * xmlRelaxNGSetParserErrors:
7365 * @ctxt: a Relax-NG validation context
7366 * @err: the error callback
7367 * @warn: the warning callback
7368 * @ctx: contextual data for the callbacks
7369 *
7370 * Set the callback functions used to handle errors for a validation context
7371 */
7372void
7373xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7374 xmlRelaxNGValidityErrorFunc err,
7375 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7376 if (ctxt == NULL)
7377 return;
7378 ctxt->error = err;
7379 ctxt->warning = warn;
7380 ctxt->userData = ctx;
7381}
Daniel Veillard409a8142003-07-18 15:16:57 +00007382
7383/**
7384 * xmlRelaxNGGetParserErrors:
7385 * @ctxt: a Relax-NG validation context
7386 * @err: the error callback result
7387 * @warn: the warning callback result
7388 * @ctx: contextual data for the callbacks result
7389 *
7390 * Get the callback information used to handle errors for a validation context
7391 *
7392 * Returns -1 in case of failure, 0 otherwise.
7393 */
7394int
7395xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7396 xmlRelaxNGValidityErrorFunc *err,
7397 xmlRelaxNGValidityWarningFunc *warn, void **ctx) {
7398 if (ctxt == NULL)
7399 return(-1);
7400 if (err != NULL) *err = ctxt->error;
7401 if (warn != NULL) *warn = ctxt->warning;
7402 if (ctx != NULL) *ctx = ctxt->userData;
7403 return(0);
7404}
7405
Daniel Veillard6eadf632003-01-23 18:29:16 +00007406/************************************************************************
7407 * *
7408 * Dump back a compiled form *
7409 * *
7410 ************************************************************************/
7411static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7412
7413/**
7414 * xmlRelaxNGDumpDefines:
7415 * @output: the file output
7416 * @defines: a list of define structures
7417 *
7418 * Dump a RelaxNG structure back
7419 */
7420static void
7421xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7422 while (defines != NULL) {
7423 xmlRelaxNGDumpDefine(output, defines);
7424 defines = defines->next;
7425 }
7426}
7427
7428/**
7429 * xmlRelaxNGDumpDefine:
7430 * @output: the file output
7431 * @define: a define structure
7432 *
7433 * Dump a RelaxNG structure back
7434 */
7435static void
7436xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7437 if (define == NULL)
7438 return;
7439 switch(define->type) {
7440 case XML_RELAXNG_EMPTY:
7441 fprintf(output, "<empty/>\n");
7442 break;
7443 case XML_RELAXNG_NOT_ALLOWED:
7444 fprintf(output, "<notAllowed/>\n");
7445 break;
7446 case XML_RELAXNG_TEXT:
7447 fprintf(output, "<text/>\n");
7448 break;
7449 case XML_RELAXNG_ELEMENT:
7450 fprintf(output, "<element>\n");
7451 if (define->name != NULL) {
7452 fprintf(output, "<name");
7453 if (define->ns != NULL)
7454 fprintf(output, " ns=\"%s\"", define->ns);
7455 fprintf(output, ">%s</name>\n", define->name);
7456 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007457 xmlRelaxNGDumpDefines(output, define->attrs);
7458 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007459 fprintf(output, "</element>\n");
7460 break;
7461 case XML_RELAXNG_LIST:
7462 fprintf(output, "<list>\n");
7463 xmlRelaxNGDumpDefines(output, define->content);
7464 fprintf(output, "</list>\n");
7465 break;
7466 case XML_RELAXNG_ONEORMORE:
7467 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007468 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007469 fprintf(output, "</oneOrMore>\n");
7470 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007471 case XML_RELAXNG_ZEROORMORE:
7472 fprintf(output, "<zeroOrMore>\n");
7473 xmlRelaxNGDumpDefines(output, define->content);
7474 fprintf(output, "</zeroOrMore>\n");
7475 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007476 case XML_RELAXNG_CHOICE:
7477 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007478 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007479 fprintf(output, "</choice>\n");
7480 break;
7481 case XML_RELAXNG_GROUP:
7482 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007483 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007484 fprintf(output, "</group>\n");
7485 break;
7486 case XML_RELAXNG_INTERLEAVE:
7487 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007488 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007489 fprintf(output, "</interleave>\n");
7490 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007491 case XML_RELAXNG_OPTIONAL:
7492 fprintf(output, "<optional>\n");
7493 xmlRelaxNGDumpDefines(output, define->content);
7494 fprintf(output, "</optional>\n");
7495 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007496 case XML_RELAXNG_ATTRIBUTE:
7497 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007498 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007499 fprintf(output, "</attribute>\n");
7500 break;
7501 case XML_RELAXNG_DEF:
7502 fprintf(output, "<define");
7503 if (define->name != NULL)
7504 fprintf(output, " name=\"%s\"", define->name);
7505 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007506 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007507 fprintf(output, "</define>\n");
7508 break;
7509 case XML_RELAXNG_REF:
7510 fprintf(output, "<ref");
7511 if (define->name != NULL)
7512 fprintf(output, " name=\"%s\"", define->name);
7513 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007514 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007515 fprintf(output, "</ref>\n");
7516 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007517 case XML_RELAXNG_PARENTREF:
7518 fprintf(output, "<parentRef");
7519 if (define->name != NULL)
7520 fprintf(output, " name=\"%s\"", define->name);
7521 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007522 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00007523 fprintf(output, "</parentRef>\n");
7524 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007525 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00007526 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007527 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00007528 fprintf(output, "</externalRef>\n");
7529 break;
7530 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007531 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007532 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00007533 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007534 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007535 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007536 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007537 TODO
7538 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007539 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007540 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00007541 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007542 }
7543}
7544
7545/**
7546 * xmlRelaxNGDumpGrammar:
7547 * @output: the file output
7548 * @grammar: a grammar structure
7549 * @top: is this a top grammar
7550 *
7551 * Dump a RelaxNG structure back
7552 */
7553static void
7554xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7555{
7556 if (grammar == NULL)
7557 return;
7558
7559 fprintf(output, "<grammar");
7560 if (top)
7561 fprintf(output,
7562 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7563 switch(grammar->combine) {
7564 case XML_RELAXNG_COMBINE_UNDEFINED:
7565 break;
7566 case XML_RELAXNG_COMBINE_CHOICE:
7567 fprintf(output, " combine=\"choice\"");
7568 break;
7569 case XML_RELAXNG_COMBINE_INTERLEAVE:
7570 fprintf(output, " combine=\"interleave\"");
7571 break;
7572 default:
7573 fprintf(output, " <!-- invalid combine value -->");
7574 }
7575 fprintf(output, ">\n");
7576 if (grammar->start == NULL) {
7577 fprintf(output, " <!-- grammar had no start -->");
7578 } else {
7579 fprintf(output, "<start>\n");
7580 xmlRelaxNGDumpDefine(output, grammar->start);
7581 fprintf(output, "</start>\n");
7582 }
7583 /* TODO ? Dump the defines ? */
7584 fprintf(output, "</grammar>\n");
7585}
7586
7587/**
7588 * xmlRelaxNGDump:
7589 * @output: the file output
7590 * @schema: a schema structure
7591 *
7592 * Dump a RelaxNG structure back
7593 */
7594void
7595xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7596{
7597 if (schema == NULL) {
7598 fprintf(output, "RelaxNG empty or failed to compile\n");
7599 return;
7600 }
7601 fprintf(output, "RelaxNG: ");
7602 if (schema->doc == NULL) {
7603 fprintf(output, "no document\n");
7604 } else if (schema->doc->URL != NULL) {
7605 fprintf(output, "%s\n", schema->doc->URL);
7606 } else {
7607 fprintf(output, "\n");
7608 }
7609 if (schema->topgrammar == NULL) {
7610 fprintf(output, "RelaxNG has no top grammar\n");
7611 return;
7612 }
7613 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7614}
7615
Daniel Veillardfebcca42003-02-16 15:44:18 +00007616/**
7617 * xmlRelaxNGDumpTree:
7618 * @output: the file output
7619 * @schema: a schema structure
7620 *
7621 * Dump the transformed RelaxNG tree.
7622 */
7623void
7624xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7625{
7626 if (schema == NULL) {
7627 fprintf(output, "RelaxNG empty or failed to compile\n");
7628 return;
7629 }
7630 if (schema->doc == NULL) {
7631 fprintf(output, "no document\n");
7632 } else {
7633 xmlDocDump(output, schema->doc);
7634 }
7635}
7636
Daniel Veillard6eadf632003-01-23 18:29:16 +00007637/************************************************************************
7638 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007639 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007640 * *
7641 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007642static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7643 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007644
7645/**
7646 * xmlRelaxNGValidateCompiledCallback:
7647 * @exec: the regular expression instance
7648 * @token: the token which matched
7649 * @transdata: callback data, the define for the subelement if available
7650 @ @inputdata: callback data, the Relax NG validation context
7651 *
7652 * Handle the callback and if needed validate the element children.
7653 */
7654static void
7655xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7656 const xmlChar *token,
7657 void *transdata,
7658 void *inputdata) {
7659 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7660 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7661 int ret;
7662
7663#ifdef DEBUG_COMPILE
7664 xmlGenericError(xmlGenericErrorContext,
7665 "Compiled callback for: '%s'\n", token);
7666#endif
7667 if (ctxt == NULL) {
7668 fprintf(stderr, "callback on %s missing context\n", token);
7669 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7670 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7671 return;
7672 }
7673 if (define == NULL) {
7674 if (token[0] == '#')
7675 return;
7676 fprintf(stderr, "callback on %s missing define\n", token);
7677 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7678 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7679 return;
7680 }
7681 if ((ctxt == NULL) || (define == NULL)) {
7682 fprintf(stderr, "callback on %s missing info\n", token);
7683 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7684 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7685 return;
7686 } else if (define->type != XML_RELAXNG_ELEMENT) {
7687 fprintf(stderr, "callback on %s define is not element\n", token);
7688 if (ctxt->errNo == XML_RELAXNG_OK)
7689 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7690 return;
7691 }
7692 ret = xmlRelaxNGValidateDefinition(ctxt, define);
7693}
7694
7695/**
7696 * xmlRelaxNGValidateCompiledContent:
7697 * @ctxt: the RelaxNG validation context
7698 * @regexp: the regular expression as compiled
7699 * @content: list of children to test against the regexp
7700 *
7701 * Validate the content model of an element or start using the regexp
7702 *
7703 * Returns 0 in case of success, -1 in case of error.
7704 */
7705static int
7706xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7707 xmlRegexpPtr regexp, xmlNodePtr content) {
7708 xmlRegExecCtxtPtr exec;
7709 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007710 int ret = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007711
7712 if ((ctxt == NULL) || (regexp == NULL))
7713 return(-1);
7714 exec = xmlRegNewExecCtxt(regexp,
7715 xmlRelaxNGValidateCompiledCallback, ctxt);
7716 cur = content;
7717 while (cur != NULL) {
7718 ctxt->state->seq = cur;
7719 switch (cur->type) {
7720 case XML_TEXT_NODE:
7721 case XML_CDATA_SECTION_NODE:
7722 if (xmlIsBlankNode(cur))
7723 break;
7724 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7725 if (ret < 0) {
7726 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7727 }
7728 break;
7729 case XML_ELEMENT_NODE:
7730 if (cur->ns != NULL) {
7731 ret = xmlRegExecPushString2(exec, cur->name,
7732 cur->ns->href, ctxt);
7733 } else {
7734 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7735 }
7736 if (ret < 0) {
7737 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7738 }
7739 break;
7740 default:
7741 break;
7742 }
7743 if (ret < 0) break;
7744 /*
7745 * Switch to next element
7746 */
7747 cur = cur->next;
7748 }
7749 ret = xmlRegExecPushString(exec, NULL, NULL);
7750 if (ret == 1) {
7751 ret = 0;
7752 ctxt->state->seq = NULL;
7753 } else if (ret == 0) {
7754 /*
Daniel Veillardf4e55762003-04-15 23:32:22 +00007755 * TODO: get some of the names needed to exit the current state of exec
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007756 */
7757 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7758 ret = -1;
7759 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7760 xmlRelaxNGDumpValidError(ctxt);
7761 } else {
7762 ret = -1;
7763 }
7764 xmlRegFreeExecCtxt(exec);
7765 return(ret);
7766}
7767
7768/************************************************************************
7769 * *
7770 * Progressive validation of when possible *
7771 * *
7772 ************************************************************************/
Daniel Veillardf4e55762003-04-15 23:32:22 +00007773static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7774 xmlRelaxNGDefinePtr defines);
7775static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt);
7776
7777/**
7778 * xmlRelaxNGElemPush:
7779 * @ctxt: the validation context
7780 * @exec: the regexp runtime for the new content model
7781 *
7782 * Push a new regexp for the current node content model on the stack
7783 *
7784 * Returns 0 in case of success and -1 in case of error.
7785 */
7786static int
7787xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) {
7788 if (ctxt->elemTab == NULL) {
7789 ctxt->elemMax = 10;
7790 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7791 sizeof(xmlRegExecCtxtPtr));
7792 if (ctxt->elemTab == NULL) {
7793 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7794 return(-1);
7795 }
7796 }
7797 if (ctxt->elemNr >= ctxt->elemMax) {
7798 ctxt->elemMax *= 2;
7799 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7800 ctxt->elemMax * sizeof(xmlRegExecCtxtPtr));
7801 if (ctxt->elemTab == NULL) {
7802 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7803 return(-1);
7804 }
7805 }
7806 ctxt->elemTab[ctxt->elemNr++] = exec;
7807 ctxt->elem = exec;
7808 return(0);
7809}
7810
7811/**
7812 * xmlRelaxNGElemPop:
7813 * @ctxt: the validation context
7814 *
7815 * Pop the regexp of the current node content model from the stack
7816 *
7817 * Returns the exec or NULL if empty
7818 */
7819static xmlRegExecCtxtPtr
7820xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) {
7821 xmlRegExecCtxtPtr ret;
7822
7823 if (ctxt->elemNr <= 0) return(NULL);
7824 ctxt->elemNr--;
7825 ret = ctxt->elemTab[ctxt->elemNr];
7826 ctxt->elemTab[ctxt->elemNr] = NULL;
7827 if (ctxt->elemNr > 0)
7828 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7829 else
7830 ctxt->elem = NULL;
7831 return(ret);
7832}
7833
7834/**
7835 * xmlRelaxNGValidateProgressiveCallback:
7836 * @exec: the regular expression instance
7837 * @token: the token which matched
7838 * @transdata: callback data, the define for the subelement if available
7839 @ @inputdata: callback data, the Relax NG validation context
7840 *
7841 * Handle the callback and if needed validate the element children.
7842 * some of the in/out informations are passed via the context in @inputdata.
7843 */
7844static void
7845xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7846 const xmlChar *token,
7847 void *transdata,
7848 void *inputdata) {
7849 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7850 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007851 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007852 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007853 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007854
7855#ifdef DEBUG_PROGRESSIVE
7856 xmlGenericError(xmlGenericErrorContext,
7857 "Progressive callback for: '%s'\n", token);
7858#endif
7859 if (ctxt == NULL) {
7860 fprintf(stderr, "callback on %s missing context\n", token);
7861 return;
7862 }
7863 ctxt->pstate = 1;
7864 if (define == NULL) {
7865 if (token[0] == '#')
7866 return;
7867 fprintf(stderr, "callback on %s missing define\n", token);
7868 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7869 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7870 ctxt->pstate = -1;
7871 return;
7872 }
7873 if ((ctxt == NULL) || (define == NULL)) {
7874 fprintf(stderr, "callback on %s missing info\n", token);
7875 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7876 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7877 ctxt->pstate = -1;
7878 return;
7879 } else if (define->type != XML_RELAXNG_ELEMENT) {
7880 fprintf(stderr, "callback on %s define is not element\n", token);
7881 if (ctxt->errNo == XML_RELAXNG_OK)
7882 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7883 ctxt->pstate = -1;
7884 return;
7885 }
7886 if (node->type != XML_ELEMENT_NODE) {
7887 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7888 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7889 xmlRelaxNGDumpValidError(ctxt);
7890 ctxt->pstate = -1;
7891 return;
7892 }
7893 if (define->contModel == NULL) {
7894 /*
7895 * this node cannot be validated in a streamable fashion
7896 */
7897#ifdef DEBUG_PROGRESSIVE
7898 xmlGenericError(xmlGenericErrorContext,
7899 "Element '%s' validation is not streamable\n", token);
7900#endif
7901 ctxt->pstate = 0;
7902 ctxt->pdef = define;
7903 return;
7904 }
7905 exec = xmlRegNewExecCtxt(define->contModel,
7906 xmlRelaxNGValidateProgressiveCallback,
7907 ctxt);
7908 if (exec == NULL) {
7909 ctxt->pstate = -1;
7910 return;
7911 }
7912 xmlRelaxNGElemPush(ctxt, exec);
7913
7914 /*
7915 * Validate the attributes part of the content.
7916 */
7917 state = xmlRelaxNGNewValidState(ctxt, node);
7918 if (state == NULL) {
7919 ctxt->pstate = -1;
7920 return;
7921 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007922 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007923 ctxt->state = state;
7924 if (define->attrs != NULL) {
7925 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7926 if (ret != 0) {
7927 ctxt->pstate = -1;
7928 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7929 }
7930 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007931 if (ctxt->state != NULL) {
7932 ctxt->state->seq = NULL;
7933 ret = xmlRelaxNGValidateElementEnd(ctxt);
7934 if (ret != 0) {
7935 ctxt->pstate = -1;
7936 }
7937 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
7938 } else if (ctxt->states != NULL) {
7939 int tmp = -1, i;
7940
7941 oldflags = ctxt->flags;
7942 ctxt->flags |= FLAGS_IGNORABLE;
7943
7944 for (i = 0; i < ctxt->states->nbState; i++) {
7945 state = ctxt->states->tabState[i];
7946 ctxt->state = state;
7947 ctxt->state->seq = NULL;
7948
7949 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7950 tmp = 0;
7951 xmlRelaxNGFreeValidState(ctxt, state);
7952 }
7953 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7954 ctxt->states = NULL;
7955 if ((ret == 0) && (tmp == -1))
7956 ctxt->pstate = -1;
7957 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007958 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007959 if (ctxt->pstate == -1) {
7960 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
7961 xmlRelaxNGDumpValidError(ctxt);
7962 }
7963 }
7964 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007965}
7966
7967/**
7968 * xmlRelaxNGValidatePushElement:
7969 * @ctxt: the validation context
7970 * @doc: a document instance
7971 * @elem: an element instance
7972 *
7973 * Push a new element start on the RelaxNG validation stack.
7974 *
7975 * returns 1 if no validation problem was found or 0 if validating the
7976 * element requires a full node, and -1 in case of error.
7977 */
7978int
Daniel Veillard33300b42003-04-17 09:09:19 +00007979xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
7980 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00007981 xmlNodePtr elem)
7982{
7983 int ret = 1;
7984
7985 if ((ctxt == NULL) || (elem == NULL))
7986 return (-1);
7987
7988#ifdef DEBUG_PROGRESSIVE
7989 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
7990#endif
7991 if (ctxt->elem == 0) {
7992 xmlRelaxNGPtr schema;
7993 xmlRelaxNGGrammarPtr grammar;
7994 xmlRegExecCtxtPtr exec;
7995 xmlRelaxNGDefinePtr define;
7996
7997 schema = ctxt->schema;
7998 if (schema == NULL) {
7999 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8000 return (-1);
8001 }
8002 grammar = schema->topgrammar;
8003 if ((grammar == NULL) || (grammar->start == NULL)) {
8004 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8005 return (-1);
8006 }
8007 define = grammar->start;
8008 if (define->contModel == NULL) {
8009 ctxt->pdef = define;
8010 return (0);
8011 }
8012 exec = xmlRegNewExecCtxt(define->contModel,
8013 xmlRelaxNGValidateProgressiveCallback,
8014 ctxt);
8015 if (exec == NULL) {
8016 return (-1);
8017 }
8018 xmlRelaxNGElemPush(ctxt, exec);
8019 }
8020 ctxt->pnode = elem;
8021 ctxt->pstate = 0;
8022 if (elem->ns != NULL) {
8023 ret =
8024 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8025 ctxt);
8026 } else {
8027 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8028 }
8029 if (ret < 0) {
8030 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8031 } else {
8032 if (ctxt->pstate == 0)
8033 ret = 0;
8034 else if (ctxt->pstate < 0)
8035 ret = -1;
8036 else
8037 ret = 1;
8038 }
8039#ifdef DEBUG_PROGRESSIVE
8040 if (ret < 0)
8041 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8042 elem->name);
8043#endif
8044 return (ret);
8045}
8046
8047/**
8048 * xmlRelaxNGValidatePushCData:
8049 * @ctxt: the RelaxNG validation context
8050 * @data: some character data read
8051 * @len: the lenght of the data
8052 *
8053 * check the CData parsed for validation in the current stack
8054 *
8055 * returns 1 if no validation problem was found or -1 otherwise
8056 */
8057int
8058xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard33300b42003-04-17 09:09:19 +00008059 const xmlChar * data,
8060 int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008061{
8062 int ret = 1;
8063
8064 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8065 return (-1);
8066
8067#ifdef DEBUG_PROGRESSIVE
8068 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8069#endif
8070
8071 while (*data != 0) {
8072 if (!IS_BLANK(*data))
8073 break;
8074 data++;
8075 }
8076 if (*data == 0)
8077 return(1);
8078
8079 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8080 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008081 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008082#ifdef DEBUG_PROGRESSIVE
8083 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
8084#endif
8085
8086 return(-1);
8087 }
8088 return(1);
8089}
8090
8091/**
8092 * xmlRelaxNGValidatePopElement:
8093 * @ctxt: the RelaxNG validation context
8094 * @doc: a document instance
8095 * @elem: an element instance
8096 *
8097 * Pop the element end from the RelaxNG validation stack.
8098 *
8099 * returns 1 if no validation problem was found or 0 otherwise
8100 */
8101int
8102xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8103 xmlDocPtr doc ATTRIBUTE_UNUSED,
8104 xmlNodePtr elem) {
8105 int ret;
8106 xmlRegExecCtxtPtr exec;
8107
8108 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) return(-1);
8109#ifdef DEBUG_PROGRESSIVE
8110 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8111#endif
8112 /*
8113 * verify that we reached a terminal state of the content model.
8114 */
8115 exec = xmlRelaxNGElemPop(ctxt);
8116 ret = xmlRegExecPushString(exec, NULL, NULL);
8117 if (ret == 0) {
8118 /*
8119 * TODO: get some of the names needed to exit the current state of exec
8120 */
8121 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8122 ret = -1;
8123 } else if (ret < 0) {
8124 ret = -1;
8125 } else {
8126 ret = 1;
8127 }
8128 xmlRegFreeExecCtxt(exec);
8129#ifdef DEBUG_PROGRESSIVE
8130 if (ret < 0)
8131 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8132 elem->name);
8133#endif
8134 return(ret);
8135}
8136
8137/**
8138 * xmlRelaxNGValidateFullElement:
8139 * @ctxt: the validation context
8140 * @doc: a document instance
8141 * @elem: an element instance
8142 *
8143 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8144 * 0 and the content of the node has been expanded.
8145 *
8146 * returns 1 if no validation problem was found or -1 in case of error.
8147 */
8148int
Daniel Veillard33300b42003-04-17 09:09:19 +00008149xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8150 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008151 xmlNodePtr elem) {
8152 int ret;
8153 xmlRelaxNGValidStatePtr state;
8154
8155 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) return(-1);
8156#ifdef DEBUG_PROGRESSIVE
8157 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8158#endif
8159 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8160 if (state == NULL) {
8161 return(-1);
8162 }
8163 state->seq = elem;
8164 ctxt->state = state;
8165 ctxt->errNo = XML_RELAXNG_OK;
8166 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8167 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) ret = -1;
8168 else ret = 1;
8169 xmlRelaxNGFreeValidState(ctxt, state);
8170 ctxt->state = NULL;
8171#ifdef DEBUG_PROGRESSIVE
8172 if (ret < 0)
8173 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8174 elem->name);
8175#endif
8176 return(ret);
8177}
8178
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008179/************************************************************************
8180 * *
8181 * Generic interpreted validation implementation *
8182 * *
8183 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008184static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8185 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008186
8187/**
8188 * xmlRelaxNGSkipIgnored:
8189 * @ctxt: a schema validation context
8190 * @node: the top node.
8191 *
8192 * Skip ignorable nodes in that context
8193 *
8194 * Returns the new sibling or NULL in case of error.
8195 */
8196static xmlNodePtr
8197xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8198 xmlNodePtr node) {
8199 /*
8200 * TODO complete and handle entities
8201 */
8202 while ((node != NULL) &&
8203 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008204 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008205 (((node->type == XML_TEXT_NODE) ||
8206 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008207 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8208 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00008209 node = node->next;
8210 }
8211 return(node);
8212}
8213
8214/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008215 * xmlRelaxNGNormalize:
8216 * @ctxt: a schema validation context
8217 * @str: the string to normalize
8218 *
8219 * Implements the normalizeWhiteSpace( s ) function from
8220 * section 6.2.9 of the spec
8221 *
8222 * Returns the new string or NULL in case of error.
8223 */
8224static xmlChar *
8225xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
8226 xmlChar *ret, *p;
8227 const xmlChar *tmp;
8228 int len;
8229
8230 if (str == NULL)
8231 return(NULL);
8232 tmp = str;
8233 while (*tmp != 0) tmp++;
8234 len = tmp - str;
8235
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008236 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008237 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008238 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008239 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008240 } else {
8241 xmlGenericError(xmlGenericErrorContext,
8242 "xmlRelaxNGNormalize: out of memory\n");
8243 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008244 return(NULL);
8245 }
8246 p = ret;
8247 while (IS_BLANK(*str)) str++;
8248 while (*str != 0) {
8249 if (IS_BLANK(*str)) {
8250 while (IS_BLANK(*str)) str++;
8251 if (*str == 0)
8252 break;
8253 *p++ = ' ';
8254 } else
8255 *p++ = *str++;
8256 }
8257 *p = 0;
8258 return(ret);
8259}
8260
8261/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008262 * xmlRelaxNGValidateDatatype:
8263 * @ctxt: a Relax-NG validation context
8264 * @value: the string value
8265 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008266 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008267 *
8268 * Validate the given value against the dataype
8269 *
8270 * Returns 0 if the validation succeeded or an error code.
8271 */
8272static int
8273xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008274 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008275 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008276 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008277 void *result = NULL;
8278 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008279
8280 if ((define == NULL) || (define->data == NULL)) {
8281 return(-1);
8282 }
8283 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008284 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008285 if ((define->attrs != NULL) &&
8286 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008287 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008288 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008289 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008290 }
8291 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008292 ret = -1;
8293 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008294 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008295 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8296 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008297 return(-1);
8298 } else if (ret == 1) {
8299 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008300 } else if (ret == 2) {
8301 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008302 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008303 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008304 ret = -1;
8305 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008306 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008307 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8308 if (lib->facet != NULL) {
8309 tmp = lib->facet(lib->data, define->name, cur->name,
8310 cur->value, value, result);
8311 if (tmp != 0)
8312 ret = -1;
8313 }
8314 cur = cur->next;
8315 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008316 if ((ret == 0) && (define->content != NULL)) {
8317 const xmlChar *oldvalue, *oldendvalue;
8318
8319 oldvalue = ctxt->state->value;
8320 oldendvalue = ctxt->state->endvalue;
8321 ctxt->state->value = (xmlChar *) value;
8322 ctxt->state->endvalue = NULL;
8323 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8324 ctxt->state->value = (xmlChar *) oldvalue;
8325 ctxt->state->endvalue = (xmlChar *) oldendvalue;
8326 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008327 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8328 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008329 return(ret);
8330}
8331
8332/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008333 * xmlRelaxNGNextValue:
8334 * @ctxt: a Relax-NG validation context
8335 *
8336 * Skip to the next value when validating within a list
8337 *
8338 * Returns 0 if the operation succeeded or an error code.
8339 */
8340static int
8341xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
8342 xmlChar *cur;
8343
8344 cur = ctxt->state->value;
8345 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8346 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00008347 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008348 return(0);
8349 }
8350 while (*cur != 0) cur++;
8351 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
8352 if (cur == ctxt->state->endvalue)
8353 ctxt->state->value = NULL;
8354 else
8355 ctxt->state->value = cur;
8356 return(0);
8357}
8358
8359/**
8360 * xmlRelaxNGValidateValueList:
8361 * @ctxt: a Relax-NG validation context
8362 * @defines: the list of definitions to verify
8363 *
8364 * Validate the given set of definitions for the current value
8365 *
8366 * Returns 0 if the validation succeeded or an error code.
8367 */
8368static int
8369xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8370 xmlRelaxNGDefinePtr defines) {
8371 int ret = 0;
8372
8373 while (defines != NULL) {
8374 ret = xmlRelaxNGValidateValue(ctxt, defines);
8375 if (ret != 0)
8376 break;
8377 defines = defines->next;
8378 }
8379 return(ret);
8380}
8381
8382/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008383 * xmlRelaxNGValidateValue:
8384 * @ctxt: a Relax-NG validation context
8385 * @define: the definition to verify
8386 *
8387 * Validate the given definition for the current value
8388 *
8389 * Returns 0 if the validation succeeded or an error code.
8390 */
8391static int
8392xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8393 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00008394 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008395 xmlChar *value;
8396
8397 value = ctxt->state->value;
8398 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008399 case XML_RELAXNG_EMPTY: {
8400 if ((value != NULL) && (value[0] != 0)) {
8401 int idx = 0;
8402
8403 while (IS_BLANK(value[idx]))
8404 idx++;
8405 if (value[idx] != 0)
8406 ret = -1;
8407 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008408 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00008409 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008410 case XML_RELAXNG_TEXT:
8411 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00008412 case XML_RELAXNG_VALUE: {
8413 if (!xmlStrEqual(value, define->value)) {
8414 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008415 xmlRelaxNGTypeLibraryPtr lib;
8416
8417 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00008418 if ((lib != NULL) && (lib->comp != NULL)) {
8419 ret = lib->comp(lib->data, define->name,
8420 define->value, define->node,
8421 (void *) define->attrs,
8422 value, ctxt->state->node);
8423 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00008424 ret = -1;
8425 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008426 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008427 return(-1);
8428 } else if (ret == 1) {
8429 ret = 0;
8430 } else {
8431 ret = -1;
8432 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008433 } else {
8434 xmlChar *nval, *nvalue;
8435
8436 /*
8437 * TODO: trivial optimizations are possible by
8438 * computing at compile-time
8439 */
8440 nval = xmlRelaxNGNormalize(ctxt, define->value);
8441 nvalue = xmlRelaxNGNormalize(ctxt, value);
8442
Daniel Veillardea3f3982003-01-26 19:45:18 +00008443 if ((nval == NULL) || (nvalue == NULL) ||
8444 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00008445 ret = -1;
8446 if (nval != NULL)
8447 xmlFree(nval);
8448 if (nvalue != NULL)
8449 xmlFree(nvalue);
8450 }
8451 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008452 if (ret == 0)
8453 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00008454 break;
8455 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008456 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008457 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8458 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008459 if (ret == 0)
8460 xmlRelaxNGNextValue(ctxt);
8461
8462 break;
8463 }
8464 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008465 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008466 xmlChar *oldvalue;
8467
8468 oldflags = ctxt->flags;
8469 ctxt->flags |= FLAGS_IGNORABLE;
8470
8471 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008472 while (list != NULL) {
8473 ret = xmlRelaxNGValidateValue(ctxt, list);
8474 if (ret == 0) {
8475 break;
8476 }
8477 ctxt->state->value = oldvalue;
8478 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008479 }
8480 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008481 if (ret != 0) {
8482 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8483 xmlRelaxNGDumpValidError(ctxt);
8484 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008485 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008486 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008487 if (ret == 0)
8488 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008489 break;
8490 }
8491 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008492 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008493 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00008494#ifdef DEBUG_LIST
8495 int nb_values = 0;
8496#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008497
8498 oldvalue = ctxt->state->value;
8499 oldend = ctxt->state->endvalue;
8500
8501 val = xmlStrdup(oldvalue);
8502 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008503 val = xmlStrdup(BAD_CAST "");
8504 }
8505 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008506 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008507 return(-1);
8508 }
8509 cur = val;
8510 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00008511 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008512 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008513 cur++;
8514#ifdef DEBUG_LIST
8515 nb_values++;
8516#endif
8517 while (IS_BLANK(*cur))
8518 *cur++ = 0;
8519 } else
8520 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008521 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008522#ifdef DEBUG_LIST
8523 xmlGenericError(xmlGenericErrorContext,
8524 "list value: '%s' found %d items\n", oldvalue, nb_values);
8525 nb_values = 0;
8526#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008527 ctxt->state->endvalue = cur;
8528 cur = val;
8529 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008530
Daniel Veillardfd573f12003-03-16 17:52:32 +00008531 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008532
Daniel Veillardfd573f12003-03-16 17:52:32 +00008533 while (list != NULL) {
8534 if (ctxt->state->value == ctxt->state->endvalue)
8535 ctxt->state->value = NULL;
8536 ret = xmlRelaxNGValidateValue(ctxt, list);
8537 if (ret != 0) {
8538#ifdef DEBUG_LIST
8539 xmlGenericError(xmlGenericErrorContext,
8540 "Failed to validate value: '%s' with %d rule\n",
8541 ctxt->state->value, nb_values);
8542#endif
8543 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008544 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008545#ifdef DEBUG_LIST
8546 nb_values++;
8547#endif
8548 list = list->next;
8549 }
8550
8551 if ((ret == 0) && (ctxt->state->value != NULL) &&
8552 (ctxt->state->value != ctxt->state->endvalue)) {
8553 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
8554 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008555 }
8556 xmlFree(val);
8557 ctxt->state->value = oldvalue;
8558 ctxt->state->endvalue = oldend;
8559 break;
8560 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008561 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008562 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8563 if (ret != 0) {
8564 break;
8565 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008566 /* no break on purpose */
8567 case XML_RELAXNG_ZEROORMORE: {
8568 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008569
8570 oldflags = ctxt->flags;
8571 ctxt->flags |= FLAGS_IGNORABLE;
8572 cur = ctxt->state->value;
8573 temp = NULL;
8574 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8575 (temp != cur)) {
8576 temp = cur;
8577 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8578 if (ret != 0) {
8579 ctxt->state->value = temp;
8580 ret = 0;
8581 break;
8582 }
8583 cur = ctxt->state->value;
8584 }
8585 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008586 if (ret != 0) {
8587 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8588 xmlRelaxNGDumpValidError(ctxt);
8589 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008590 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008591 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008592 break;
8593 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008594 case XML_RELAXNG_EXCEPT: {
8595 xmlRelaxNGDefinePtr list;
8596
8597 list = define->content;
8598 while (list != NULL) {
8599 ret = xmlRelaxNGValidateValue(ctxt, list);
8600 if (ret == 0) {
8601 ret = -1;
8602 break;
8603 } else
8604 ret = 0;
8605 list = list->next;
8606 }
8607 break;
8608 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008609 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008610 case XML_RELAXNG_GROUP: {
8611 xmlRelaxNGDefinePtr list;
8612
8613 list = define->content;
8614 while (list != NULL) {
8615 ret = xmlRelaxNGValidateValue(ctxt, list);
8616 if (ret != 0) {
8617 ret = -1;
8618 break;
8619 } else
8620 ret = 0;
8621 list = list->next;
8622 }
Daniel Veillardd4310742003-02-18 21:12:46 +00008623 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008624 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008625 case XML_RELAXNG_REF:
8626 case XML_RELAXNG_PARENTREF:
8627 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8628 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008629 default:
8630 TODO
8631 ret = -1;
8632 }
8633 return(ret);
8634}
8635
8636/**
8637 * xmlRelaxNGValidateValueContent:
8638 * @ctxt: a Relax-NG validation context
8639 * @defines: the list of definitions to verify
8640 *
8641 * Validate the given definitions for the current value
8642 *
8643 * Returns 0 if the validation succeeded or an error code.
8644 */
8645static int
8646xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8647 xmlRelaxNGDefinePtr defines) {
8648 int ret = 0;
8649
8650 while (defines != NULL) {
8651 ret = xmlRelaxNGValidateValue(ctxt, defines);
8652 if (ret != 0)
8653 break;
8654 defines = defines->next;
8655 }
8656 return(ret);
8657}
8658
8659/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008660 * xmlRelaxNGAttributeMatch:
8661 * @ctxt: a Relax-NG validation context
8662 * @define: the definition to check
8663 * @prop: the attribute
8664 *
8665 * Check if the attribute matches the definition nameClass
8666 *
8667 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8668 */
8669static int
8670xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8671 xmlRelaxNGDefinePtr define,
8672 xmlAttrPtr prop) {
8673 int ret;
8674
8675 if (define->name != NULL) {
8676 if (!xmlStrEqual(define->name, prop->name))
8677 return(0);
8678 }
8679 if (define->ns != NULL) {
8680 if (define->ns[0] == 0) {
8681 if (prop->ns != NULL)
8682 return(0);
8683 } else {
8684 if ((prop->ns == NULL) ||
8685 (!xmlStrEqual(define->ns, prop->ns->href)))
8686 return(0);
8687 }
8688 }
8689 if (define->nameClass == NULL)
8690 return(1);
8691 define = define->nameClass;
8692 if (define->type == XML_RELAXNG_EXCEPT) {
8693 xmlRelaxNGDefinePtr list;
8694
8695 list = define->content;
8696 while (list != NULL) {
8697 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8698 if (ret == 1)
8699 return(0);
8700 if (ret < 0)
8701 return(ret);
8702 list = list->next;
8703 }
8704 } else {
8705 TODO
8706 }
8707 return(1);
8708}
8709
8710/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008711 * xmlRelaxNGValidateAttribute:
8712 * @ctxt: a Relax-NG validation context
8713 * @define: the definition to verify
8714 *
8715 * Validate the given attribute definition for that node
8716 *
8717 * Returns 0 if the validation succeeded or an error code.
8718 */
8719static int
8720xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8721 xmlRelaxNGDefinePtr define) {
8722 int ret = 0, i;
8723 xmlChar *value, *oldvalue;
8724 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008725 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008726
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008727 if (ctxt->state->nbAttrLeft <= 0)
8728 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008729 if (define->name != NULL) {
8730 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8731 tmp = ctxt->state->attrs[i];
8732 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8733 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8734 (tmp->ns == NULL)) ||
8735 ((tmp->ns != NULL) &&
8736 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8737 prop = tmp;
8738 break;
8739 }
8740 }
8741 }
8742 if (prop != NULL) {
8743 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8744 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008745 oldseq = ctxt->state->seq;
8746 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008747 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00008748 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008749 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008750 if (ctxt->state->value != NULL)
8751 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008752 if (value != NULL)
8753 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008754 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008755 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008756 if (ret == 0) {
8757 /*
8758 * flag the attribute as processed
8759 */
8760 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008761 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008762 }
8763 } else {
8764 ret = -1;
8765 }
8766#ifdef DEBUG
8767 xmlGenericError(xmlGenericErrorContext,
8768 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8769#endif
8770 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008771 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8772 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00008773 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00008774 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008775 prop = tmp;
8776 break;
8777 }
8778 }
8779 if (prop != NULL) {
8780 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8781 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008782 oldseq = ctxt->state->seq;
8783 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008784 ctxt->state->value = value;
8785 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008786 if (ctxt->state->value != NULL)
8787 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008788 if (value != NULL)
8789 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008790 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008791 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008792 if (ret == 0) {
8793 /*
8794 * flag the attribute as processed
8795 */
8796 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008797 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008798 }
8799 } else {
8800 ret = -1;
8801 }
8802#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00008803 if (define->ns != NULL) {
8804 xmlGenericError(xmlGenericErrorContext,
8805 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8806 define->ns, ret);
8807 } else {
8808 xmlGenericError(xmlGenericErrorContext,
8809 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8810 ret);
8811 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008812#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008813 }
8814
8815 return(ret);
8816}
8817
8818/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008819 * xmlRelaxNGValidateAttributeList:
8820 * @ctxt: a Relax-NG validation context
8821 * @define: the list of definition to verify
8822 *
8823 * Validate the given node against the list of attribute definitions
8824 *
8825 * Returns 0 if the validation succeeded or an error code.
8826 */
8827static int
8828xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8829 xmlRelaxNGDefinePtr defines) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00008830 int ret = 0, res;
8831 int needmore = 0;
8832 xmlRelaxNGDefinePtr cur;
8833
8834 cur = defines;
8835 while (cur != NULL) {
8836 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
8837 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8838 ret = -1;
8839 } else
8840 needmore = 1;
8841 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008842 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008843 if (!needmore)
8844 return(ret);
8845 cur = defines;
8846 while (cur != NULL) {
8847 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
8848 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8849 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8850 if (res < 0)
8851 ret = -1;
8852 } else {
8853 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8854 return(-1);
8855 }
8856 if (res == -1) /* continues on -2 */
8857 break;
8858 }
8859 cur = cur->next;
8860 }
8861
Daniel Veillardfd573f12003-03-16 17:52:32 +00008862 return(ret);
8863}
8864
8865/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008866 * xmlRelaxNGNodeMatchesList:
8867 * @node: the node
8868 * @list: a NULL terminated array of definitions
8869 *
8870 * Check if a node can be matched by one of the definitions
8871 *
8872 * Returns 1 if matches 0 otherwise
8873 */
8874static int
8875xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8876 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008877 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008878
8879 if ((node == NULL) || (list == NULL))
8880 return(0);
8881
8882 cur = list[i++];
8883 while (cur != NULL) {
8884 if ((node->type == XML_ELEMENT_NODE) &&
8885 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008886 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8887 if (tmp == 1)
8888 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008889 } else if (((node->type == XML_TEXT_NODE) ||
8890 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008891 (cur->type == XML_RELAXNG_TEXT)) {
8892 return(1);
8893 }
8894 cur = list[i++];
8895 }
8896 return(0);
8897}
8898
8899/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008900 * xmlRelaxNGValidateInterleave:
8901 * @ctxt: a Relax-NG validation context
8902 * @define: the definition to verify
8903 *
8904 * Validate an interleave definition for a node.
8905 *
8906 * Returns 0 if the validation succeeded or an error code.
8907 */
8908static int
8909xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
8910 xmlRelaxNGDefinePtr define) {
William M. Brack779af002003-08-01 15:55:39 +00008911 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008912 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008913 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008914
8915 xmlRelaxNGValidStatePtr oldstate;
8916 xmlRelaxNGPartitionPtr partitions;
8917 xmlRelaxNGInterleaveGroupPtr group = NULL;
8918 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8919 xmlNodePtr *list = NULL, *lasts = NULL;
8920
8921 if (define->data != NULL) {
8922 partitions = (xmlRelaxNGPartitionPtr) define->data;
8923 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008924 } else {
8925 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8926 return(-1);
8927 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008928 /*
8929 * Optimizations for MIXED
8930 */
8931 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00008932 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008933 ctxt->flags |= FLAGS_MIXED_CONTENT;
8934 if (nbgroups == 2) {
8935 /*
8936 * this is a pure <mixed> case
8937 */
8938 if (ctxt->state != NULL)
8939 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8940 ctxt->state->seq);
8941 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8942 ret = xmlRelaxNGValidateDefinition(ctxt,
8943 partitions->groups[1]->rule);
8944 else
8945 ret = xmlRelaxNGValidateDefinition(ctxt,
8946 partitions->groups[0]->rule);
8947 if (ret == 0) {
8948 if (ctxt->state != NULL)
8949 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8950 ctxt->state->seq);
8951 }
8952 ctxt->flags = oldflags;
8953 return(ret);
8954 }
8955 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008956
8957 /*
8958 * Build arrays to store the first and last node of the chain
8959 * pertaining to each group
8960 */
8961 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8962 if (list == NULL) {
8963 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8964 return(-1);
8965 }
8966 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8967 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8968 if (lasts == NULL) {
8969 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8970 return(-1);
8971 }
8972 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8973
8974 /*
8975 * Walk the sequence of children finding the right group and
8976 * sorting them in sequences.
8977 */
8978 cur = ctxt->state->seq;
8979 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8980 start = cur;
8981 while (cur != NULL) {
8982 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008983 if ((partitions->triage != NULL) &&
8984 (partitions->flags & IS_DETERMINIST)) {
8985 void *tmp = NULL;
8986
8987 if ((cur->type == XML_TEXT_NODE) ||
8988 (cur->type == XML_CDATA_SECTION_NODE)) {
8989 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8990 NULL);
8991 } else if (cur->type == XML_ELEMENT_NODE) {
8992 if (cur->ns != NULL) {
8993 tmp = xmlHashLookup2(partitions->triage, cur->name,
8994 cur->ns->href);
8995 if (tmp == NULL)
8996 tmp = xmlHashLookup2(partitions->triage,
8997 BAD_CAST "#any", cur->ns->href);
8998 } else
8999 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
9000 if (tmp == NULL)
9001 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9002 NULL);
9003 }
9004
9005 if (tmp == NULL) {
9006 i = nbgroups;
9007 } else {
9008 i = ((long) tmp) - 1;
9009 if (partitions->flags & IS_NEEDCHECK) {
9010 group = partitions->groups[i];
9011 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9012 i = nbgroups;
9013 }
9014 }
9015 } else {
9016 for (i = 0;i < nbgroups;i++) {
9017 group = partitions->groups[i];
9018 if (group == NULL)
9019 continue;
9020 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9021 break;
9022 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009023 }
9024 /*
9025 * We break as soon as an element not matched is found
9026 */
9027 if (i >= nbgroups) {
9028 break;
9029 }
9030 if (lasts[i] != NULL) {
9031 lasts[i]->next = cur;
9032 lasts[i] = cur;
9033 } else {
9034 list[i] = cur;
9035 lasts[i] = cur;
9036 }
9037 if (cur->next != NULL)
9038 lastchg = cur->next;
9039 else
9040 lastchg = cur;
9041 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9042 }
9043 if (ret != 0) {
9044 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9045 ret = -1;
9046 goto done;
9047 }
9048 lastelem = cur;
9049 oldstate = ctxt->state;
9050 for (i = 0;i < nbgroups;i++) {
9051 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9052 group = partitions->groups[i];
9053 if (lasts[i] != NULL) {
9054 last = lasts[i]->next;
9055 lasts[i]->next = NULL;
9056 }
9057 ctxt->state->seq = list[i];
9058 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9059 if (ret != 0)
9060 break;
9061 if (ctxt->state != NULL) {
9062 cur = ctxt->state->seq;
9063 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00009064 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009065 oldstate = ctxt->state;
9066 ctxt->state = NULL;
9067 if (cur != NULL) {
9068 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9069 ret = -1;
9070 ctxt->state = oldstate;
9071 goto done;
9072 }
9073 } else if (ctxt->states != NULL) {
9074 int j;
9075 int found = 0;
9076
9077 for (j = 0;j < ctxt->states->nbState;j++) {
9078 cur = ctxt->states->tabState[j]->seq;
9079 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9080 if (cur == NULL) {
9081 found = 1;
9082 break;
9083 }
9084 }
9085 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009086 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009087 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
9088 }
9089 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009090 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009091 }
9092 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9093 ctxt->states = NULL;
9094 if (found == 0) {
9095 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9096 ret = -1;
9097 ctxt->state = oldstate;
9098 goto done;
9099 }
9100 } else {
9101 ret = -1;
9102 break;
9103 }
9104 if (lasts[i] != NULL) {
9105 lasts[i]->next = last;
9106 }
9107 }
9108 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009109 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009110 ctxt->state = oldstate;
9111 ctxt->state->seq = lastelem;
9112 if (ret != 0) {
9113 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9114 ret = -1;
9115 goto done;
9116 }
9117
9118done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009119 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009120 /*
9121 * builds the next links chain from the prev one
9122 */
9123 cur = lastchg;
9124 while (cur != NULL) {
9125 if ((cur == start) || (cur->prev == NULL))
9126 break;
9127 cur->prev->next = cur;
9128 cur = cur->prev;
9129 }
9130 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00009131 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009132 }
9133
9134 xmlFree(list);
9135 xmlFree(lasts);
9136 return(ret);
9137}
9138
9139/**
9140 * xmlRelaxNGValidateDefinitionList:
9141 * @ctxt: a Relax-NG validation context
9142 * @define: the list of definition to verify
9143 *
9144 * Validate the given node content against the (list) of definitions
9145 *
9146 * Returns 0 if the validation succeeded or an error code.
9147 */
9148static int
9149xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9150 xmlRelaxNGDefinePtr defines) {
9151 int ret = 0, res;
9152
9153
Daniel Veillard952379b2003-03-17 15:37:12 +00009154 if (defines == NULL) {
9155 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
9156 return(-1);
9157 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009158 while (defines != NULL) {
9159 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9160 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9161 if (res < 0)
9162 ret = -1;
9163 } else {
9164 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9165 return(-1);
9166 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009167 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00009168 break;
9169 defines = defines->next;
9170 }
9171
9172 return(ret);
9173}
9174
9175/**
9176 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009177 * @ctxt: a Relax-NG validation context
9178 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009179 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009180 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009181 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009182 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009183 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009184 */
9185static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009186xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9187 xmlRelaxNGDefinePtr define,
9188 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00009189 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009190
Daniel Veillardfd573f12003-03-16 17:52:32 +00009191 if (define->name != NULL) {
9192 if (!xmlStrEqual(elem->name, define->name)) {
9193 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9194 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009195 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009196 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009197 if ((define->ns != NULL) && (define->ns[0] != 0)) {
9198 if (elem->ns == NULL) {
9199 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
9200 elem->name);
9201 return(0);
9202 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9203 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9204 elem->name, define->ns);
9205 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009206 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009207 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9208 (define->name == NULL)) {
9209 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9210 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009211 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009212 } else if ((elem->ns != NULL) && (define->name != NULL)) {
9213 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9214 define->name);
9215 return(0);
9216 }
9217
9218 if (define->nameClass == NULL)
9219 return(1);
9220
9221 define = define->nameClass;
9222 if (define->type == XML_RELAXNG_EXCEPT) {
9223 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009224 if (ctxt != NULL) {
9225 oldflags = ctxt->flags;
9226 ctxt->flags |= FLAGS_IGNORABLE;
9227 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009228
9229 list = define->content;
9230 while (list != NULL) {
9231 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9232 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009233 if (ctxt != NULL)
9234 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009235 return(0);
9236 }
9237 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009238 if (ctxt != NULL)
9239 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009240 return(ret);
9241 }
9242 list = list->next;
9243 }
9244 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009245 if (ctxt != NULL) {
9246 ctxt->flags = oldflags;
9247 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009248 } else if (define->type == XML_RELAXNG_CHOICE) {
9249 xmlRelaxNGDefinePtr list;
9250
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009251 if (ctxt != NULL) {
9252 oldflags = ctxt->flags;
9253 ctxt->flags |= FLAGS_IGNORABLE;
9254 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009255
9256 list = define->nameClass;
9257 while (list != NULL) {
9258 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9259 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009260 if (ctxt != NULL)
9261 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009262 return(1);
9263 }
9264 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009265 if (ctxt != NULL)
9266 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009267 return(ret);
9268 }
9269 list = list->next;
9270 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009271 if (ctxt != NULL) {
9272 if (ret != 0) {
9273 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9274 xmlRelaxNGDumpValidError(ctxt);
9275 } else {
9276 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
9277 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009278 }
9279 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009280 if (ctxt != NULL) {
9281 ctxt->flags = oldflags;
9282 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009283 } else {
9284 TODO
9285 ret = -1;
9286 }
9287 return(ret);
9288}
9289
9290/**
9291 * xmlRelaxNGValidateElementEnd:
9292 * @ctxt: a Relax-NG validation context
9293 *
9294 * Validate the end of the element, implements check that
9295 * there is nothing left not consumed in the element content
9296 * or in the attribute list.
9297 *
9298 * Returns 0 if the validation succeeded or an error code.
9299 */
9300static int
9301xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
9302 int ret = 0, i;
9303 xmlRelaxNGValidStatePtr state;
9304
9305 state = ctxt->state;
9306 if (state->seq != NULL) {
9307 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9308 if (state->seq != NULL) {
9309 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9310 state->node->name, state->seq->name);
9311 ret = -1;
9312 }
9313 }
9314 for (i = 0;i < state->nbAttrs;i++) {
9315 if (state->attrs[i] != NULL) {
9316 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9317 state->attrs[i]->name, state->node->name);
9318 ret = -1;
9319 }
9320 }
9321 return(ret);
9322}
9323
9324/**
9325 * xmlRelaxNGValidateState:
9326 * @ctxt: a Relax-NG validation context
9327 * @define: the definition to verify
9328 *
9329 * Validate the current state against the definition
9330 *
9331 * Returns 0 if the validation succeeded or an error code.
9332 */
9333static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009334xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9335 xmlRelaxNGDefinePtr define)
9336{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009337 xmlNodePtr node;
9338 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009339 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009340
9341 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009342 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9343 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009344 }
9345
9346 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009347 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009348 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009349 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009350 }
9351#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009352 for (i = 0; i < ctxt->depth; i++)
9353 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009355 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009356 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009357 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009358 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009359 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009360 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009361 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009362#endif
9363 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009364 switch (define->type) {
9365 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009366 node = xmlRelaxNGSkipIgnored(ctxt, node);
9367 ret = 0;
9368 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009369 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009370 ret = -1;
9371 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009372 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009373 while ((node != NULL) &&
9374 ((node->type == XML_TEXT_NODE) ||
9375 (node->type == XML_COMMENT_NODE) ||
9376 (node->type == XML_PI_NODE) ||
9377 (node->type == XML_CDATA_SECTION_NODE)))
9378 node = node->next;
9379 ctxt->state->seq = node;
9380 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009381 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009382 errNr = ctxt->errNr;
9383 node = xmlRelaxNGSkipIgnored(ctxt, node);
9384 if (node == NULL) {
9385 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9386 ret = -1;
9387 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9388 xmlRelaxNGDumpValidError(ctxt);
9389 break;
9390 }
9391 if (node->type != XML_ELEMENT_NODE) {
9392 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9393 ret = -1;
9394 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9395 xmlRelaxNGDumpValidError(ctxt);
9396 break;
9397 }
9398 /*
9399 * This node was already validated successfully against
9400 * this definition.
9401 */
9402 if (node->_private == define) {
9403 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9404 if (ctxt->errNr > errNr)
9405 xmlRelaxNGPopErrors(ctxt, errNr);
9406 if (ctxt->errNr != 0) {
9407 while ((ctxt->err != NULL) &&
9408 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9409 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9410 ||
9411 ((ctxt->err->err ==
9412 XML_RELAXNG_ERR_ELEMEXTRANS)
9413 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9414 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9415 || (ctxt->err->err ==
9416 XML_RELAXNG_ERR_NOTELEM)))
9417 xmlRelaxNGValidErrorPop(ctxt);
9418 }
9419 break;
9420 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009421
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009422 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9423 if (ret <= 0) {
9424 ret = -1;
9425 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9426 xmlRelaxNGDumpValidError(ctxt);
9427 break;
9428 }
9429 ret = 0;
9430 if (ctxt->errNr != 0) {
9431 if (ctxt->errNr > errNr)
9432 xmlRelaxNGPopErrors(ctxt, errNr);
9433 while ((ctxt->err != NULL) &&
9434 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9435 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9436 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9437 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9438 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9439 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9440 xmlRelaxNGValidErrorPop(ctxt);
9441 }
9442 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009443
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009444 oldflags = ctxt->flags;
9445 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9446 ctxt->flags -= FLAGS_MIXED_CONTENT;
9447 }
9448 state = xmlRelaxNGNewValidState(ctxt, node);
9449 if (state == NULL) {
9450 ret = -1;
9451 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9452 xmlRelaxNGDumpValidError(ctxt);
9453 break;
9454 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009455
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009456 oldstate = ctxt->state;
9457 ctxt->state = state;
9458 if (define->attrs != NULL) {
9459 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9460 if (tmp != 0) {
9461 ret = -1;
9462 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9463 }
9464 }
9465 if (define->contModel != NULL) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009466 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9467 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9468 xmlNodePtr nseq;
9469
9470 nstate = xmlRelaxNGNewValidState(ctxt, node);
9471 ctxt->state = nstate;
9472 ctxt->states = NULL;
9473
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009474 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9475 define->contModel,
9476 ctxt->state->seq);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009477 nseq = ctxt->state->seq;
9478 ctxt->state = tmpstate;
9479 ctxt->states = tmpstates;
9480 xmlRelaxNGFreeValidState(ctxt, nstate);
9481
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009482#ifdef DEBUG_COMPILE
9483 xmlGenericError(xmlGenericErrorContext,
9484 "Validating content of '%s' : %d\n", define->name, tmp);
9485#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009486 if (tmp != 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009487 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009488
9489 if (ctxt->states != NULL) {
9490 tmp = -1;
9491
9492 ctxt->flags |= FLAGS_IGNORABLE;
9493
9494 for (i = 0; i < ctxt->states->nbState; i++) {
9495 state = ctxt->states->tabState[i];
9496 ctxt->state = state;
9497 ctxt->state->seq = nseq;
9498
9499 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9500 tmp = 0;
9501 xmlRelaxNGFreeValidState(ctxt, state);
9502 }
9503 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9504 ctxt->flags = oldflags;
9505 ctxt->states = NULL;
9506 if ((ret == 0) && (tmp == -1))
9507 ret = -1;
9508 } else {
9509 state = ctxt->state;
9510 ctxt->state->seq = nseq;
9511 if (ret == 0)
9512 ret = xmlRelaxNGValidateElementEnd(ctxt);
9513 xmlRelaxNGFreeValidState(ctxt, state);
9514 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009515 } else {
9516 if (define->content != NULL) {
9517 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9518 define->content);
9519 if (tmp != 0) {
9520 ret = -1;
9521 if (ctxt->state == NULL) {
9522 ctxt->state = oldstate;
9523 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9524 node->name);
9525 ctxt->state = NULL;
9526 } else {
9527 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9528 node->name);
9529 }
9530
9531 }
9532 }
9533 if (ctxt->states != NULL) {
9534 tmp = -1;
9535
9536 ctxt->flags |= FLAGS_IGNORABLE;
9537
9538 for (i = 0; i < ctxt->states->nbState; i++) {
9539 state = ctxt->states->tabState[i];
9540 ctxt->state = state;
9541
9542 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9543 tmp = 0;
9544 xmlRelaxNGFreeValidState(ctxt, state);
9545 }
9546 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9547 ctxt->flags = oldflags;
9548 ctxt->states = NULL;
9549 if ((ret == 0) && (tmp == -1))
9550 ret = -1;
9551 } else {
9552 state = ctxt->state;
9553 if (ret == 0)
9554 ret = xmlRelaxNGValidateElementEnd(ctxt);
9555 xmlRelaxNGFreeValidState(ctxt, state);
9556 }
9557 }
9558 if (ret == 0) {
9559 node->_private = define;
9560 }
9561 ctxt->flags = oldflags;
9562 ctxt->state = oldstate;
9563 if (oldstate != NULL)
9564 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9565 if (ret != 0) {
9566 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9567 xmlRelaxNGDumpValidError(ctxt);
9568 ret = 0;
9569 } else {
9570 ret = -2;
9571 }
9572 } else {
9573 if (ctxt->errNr > errNr)
9574 xmlRelaxNGPopErrors(ctxt, errNr);
9575 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009576
9577#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009578 xmlGenericError(xmlGenericErrorContext,
9579 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9580 node->name, ret);
9581 if (oldstate == NULL)
9582 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9583 else if (oldstate->seq == NULL)
9584 xmlGenericError(xmlGenericErrorContext, ": done\n");
9585 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9586 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9587 oldstate->seq->name);
9588 else
9589 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9590 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009591#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009592 break;
9593 case XML_RELAXNG_OPTIONAL:{
9594 errNr = ctxt->errNr;
9595 oldflags = ctxt->flags;
9596 ctxt->flags |= FLAGS_IGNORABLE;
9597 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9598 ret =
9599 xmlRelaxNGValidateDefinitionList(ctxt,
9600 define->content);
9601 if (ret != 0) {
9602 if (ctxt->state != NULL)
9603 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9604 ctxt->state = oldstate;
9605 ctxt->flags = oldflags;
9606 ret = 0;
9607 if (ctxt->errNr > errNr)
9608 xmlRelaxNGPopErrors(ctxt, errNr);
9609 break;
9610 }
9611 if (ctxt->states != NULL) {
9612 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9613 } else {
9614 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9615 if (ctxt->states == NULL) {
9616 xmlRelaxNGFreeValidState(ctxt, oldstate);
9617 ctxt->flags = oldflags;
9618 ret = -1;
9619 if (ctxt->errNr > errNr)
9620 xmlRelaxNGPopErrors(ctxt, errNr);
9621 break;
9622 }
9623 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9624 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9625 ctxt->state = NULL;
9626 }
9627 ctxt->flags = oldflags;
9628 ret = 0;
9629 if (ctxt->errNr > errNr)
9630 xmlRelaxNGPopErrors(ctxt, errNr);
9631 break;
9632 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009633 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009634 errNr = ctxt->errNr;
9635 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9636 if (ret != 0) {
9637 break;
9638 }
9639 if (ctxt->errNr > errNr)
9640 xmlRelaxNGPopErrors(ctxt, errNr);
9641 /* no break on purpose */
9642 case XML_RELAXNG_ZEROORMORE:{
9643 int progress;
9644 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9645 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009646
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009647 errNr = ctxt->errNr;
9648 res = xmlRelaxNGNewStates(ctxt, 1);
9649 if (res == NULL) {
9650 ret = -1;
9651 break;
9652 }
9653 /*
9654 * All the input states are also exit states
9655 */
9656 if (ctxt->state != NULL) {
9657 xmlRelaxNGAddStates(ctxt, res,
9658 xmlRelaxNGCopyValidState(ctxt,
9659 ctxt->
9660 state));
9661 } else {
9662 for (j = 0; j < ctxt->states->nbState; j++) {
9663 xmlRelaxNGAddStates(ctxt, res,
9664 xmlRelaxNGCopyValidState(ctxt,
9665 ctxt->
9666 states->
9667 tabState
9668 [j]));
9669 }
9670 }
9671 oldflags = ctxt->flags;
9672 ctxt->flags |= FLAGS_IGNORABLE;
9673 do {
9674 progress = 0;
9675 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009676
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009677 if (ctxt->states != NULL) {
9678 states = ctxt->states;
9679 for (i = 0; i < states->nbState; i++) {
9680 ctxt->state = states->tabState[i];
9681 ctxt->states = NULL;
9682 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9683 define->
9684 content);
9685 if (ret == 0) {
9686 if (ctxt->state != NULL) {
9687 tmp = xmlRelaxNGAddStates(ctxt, res,
9688 ctxt->state);
9689 ctxt->state = NULL;
9690 if (tmp == 1)
9691 progress = 1;
9692 } else if (ctxt->states != NULL) {
9693 for (j = 0; j < ctxt->states->nbState;
9694 j++) {
9695 tmp =
9696 xmlRelaxNGAddStates(ctxt, res,
9697 ctxt->
9698 states->
9699 tabState
9700 [j]);
9701 if (tmp == 1)
9702 progress = 1;
9703 }
9704 xmlRelaxNGFreeStates(ctxt,
9705 ctxt->states);
9706 ctxt->states = NULL;
9707 }
9708 } else {
9709 if (ctxt->state != NULL) {
9710 xmlRelaxNGFreeValidState(ctxt,
9711 ctxt->state);
9712 ctxt->state = NULL;
9713 }
9714 }
9715 }
9716 } else {
9717 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9718 define->
9719 content);
9720 if (ret != 0) {
9721 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9722 ctxt->state = NULL;
9723 } else {
9724 base = res->nbState;
9725 if (ctxt->state != NULL) {
9726 tmp = xmlRelaxNGAddStates(ctxt, res,
9727 ctxt->state);
9728 ctxt->state = NULL;
9729 if (tmp == 1)
9730 progress = 1;
9731 } else if (ctxt->states != NULL) {
9732 for (j = 0; j < ctxt->states->nbState; j++) {
9733 tmp = xmlRelaxNGAddStates(ctxt, res,
9734 ctxt->
9735 states->
9736 tabState[j]);
9737 if (tmp == 1)
9738 progress = 1;
9739 }
9740 if (states == NULL) {
9741 states = ctxt->states;
9742 } else {
9743 xmlRelaxNGFreeStates(ctxt,
9744 ctxt->states);
9745 }
9746 ctxt->states = NULL;
9747 }
9748 }
9749 }
9750 if (progress) {
9751 /*
9752 * Collect all the new nodes added at that step
9753 * and make them the new node set
9754 */
9755 if (res->nbState - base == 1) {
9756 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9757 res->
9758 tabState
9759 [base]);
9760 } else {
9761 if (states == NULL) {
9762 xmlRelaxNGNewStates(ctxt,
9763 res->nbState - base);
9764 }
9765 states->nbState = 0;
9766 for (i = base; i < res->nbState; i++)
9767 xmlRelaxNGAddStates(ctxt, states,
9768 xmlRelaxNGCopyValidState
9769 (ctxt,
9770 res->tabState[i]));
9771 ctxt->states = states;
9772 }
9773 }
9774 } while (progress == 1);
9775 if (states != NULL) {
9776 xmlRelaxNGFreeStates(ctxt, states);
9777 }
9778 ctxt->states = res;
9779 ctxt->flags = oldflags;
9780 if (ctxt->errNr > errNr)
9781 xmlRelaxNGPopErrors(ctxt, errNr);
9782 ret = 0;
9783 break;
9784 }
9785 case XML_RELAXNG_CHOICE:{
9786 xmlRelaxNGDefinePtr list = NULL;
9787 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009788
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009789 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009790
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009791 errNr = ctxt->errNr;
9792 if ((define->dflags & IS_TRIABLE)
9793 && (define->data != NULL)) {
9794 xmlHashTablePtr triage =
9795 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +00009796
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009797 /*
9798 * Something we can optimize cleanly there is only one
9799 * possble branch out !
9800 */
9801 if (node == NULL) {
9802 ret = -1;
9803 break;
9804 }
9805 if ((node->type == XML_TEXT_NODE) ||
9806 (node->type == XML_CDATA_SECTION_NODE)) {
9807 list =
9808 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9809 } else if (node->type == XML_ELEMENT_NODE) {
9810 if (node->ns != NULL) {
9811 list = xmlHashLookup2(triage, node->name,
9812 node->ns->href);
9813 if (list == NULL)
9814 list =
9815 xmlHashLookup2(triage, BAD_CAST "#any",
9816 node->ns->href);
9817 } else
9818 list =
9819 xmlHashLookup2(triage, node->name, NULL);
9820 if (list == NULL)
9821 list =
9822 xmlHashLookup2(triage, BAD_CAST "#any",
9823 NULL);
9824 }
9825 if (list == NULL) {
9826 ret = -1;
9827 break;
9828 }
9829 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9830 if (ret == 0) {
9831 }
9832 break;
9833 }
Daniel Veillarde063f482003-03-21 16:53:17 +00009834
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009835 list = define->content;
9836 oldflags = ctxt->flags;
9837 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009838
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009839 while (list != NULL) {
9840 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9841 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9842 if (ret == 0) {
9843 if (states == NULL) {
9844 states = xmlRelaxNGNewStates(ctxt, 1);
9845 }
9846 if (ctxt->state != NULL) {
9847 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9848 } else if (ctxt->states != NULL) {
9849 for (i = 0; i < ctxt->states->nbState; i++) {
9850 xmlRelaxNGAddStates(ctxt, states,
9851 ctxt->states->
9852 tabState[i]);
9853 }
9854 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9855 ctxt->states = NULL;
9856 }
9857 } else {
9858 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9859 }
9860 ctxt->state = oldstate;
9861 list = list->next;
9862 }
9863 if (states != NULL) {
9864 xmlRelaxNGFreeValidState(ctxt, oldstate);
9865 ctxt->states = states;
9866 ctxt->state = NULL;
9867 ret = 0;
9868 } else {
9869 ctxt->states = NULL;
9870 }
9871 ctxt->flags = oldflags;
9872 if (ret != 0) {
9873 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9874 xmlRelaxNGDumpValidError(ctxt);
9875 }
9876 } else {
9877 if (ctxt->errNr > errNr)
9878 xmlRelaxNGPopErrors(ctxt, errNr);
9879 }
9880 break;
9881 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009882 case XML_RELAXNG_DEF:
9883 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009884 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9885 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009886 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009887 ret = xmlRelaxNGValidateInterleave(ctxt, define);
9888 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009889 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009890 ret = xmlRelaxNGValidateAttribute(ctxt, define);
9891 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +00009892 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009893 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00009894 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009895 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +00009896 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009897 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9898 break;
9899 case XML_RELAXNG_DATATYPE:{
9900 xmlNodePtr child;
9901 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009902
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009903 child = node;
9904 while (child != NULL) {
9905 if (child->type == XML_ELEMENT_NODE) {
9906 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9907 node->parent->name);
9908 ret = -1;
9909 break;
9910 } else if ((child->type == XML_TEXT_NODE) ||
9911 (child->type == XML_CDATA_SECTION_NODE)) {
9912 content = xmlStrcat(content, child->content);
9913 }
9914 /* TODO: handle entities ... */
9915 child = child->next;
9916 }
9917 if (ret == -1) {
9918 if (content != NULL)
9919 xmlFree(content);
9920 break;
9921 }
9922 if (content == NULL) {
9923 content = xmlStrdup(BAD_CAST "");
9924 if (content == NULL) {
9925 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9926 ret = -1;
9927 break;
9928 }
9929 }
9930 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9931 ctxt->state->seq);
9932 if (ret == -1) {
9933 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9934 } else if (ret == 0) {
9935 ctxt->state->seq = NULL;
9936 }
9937 if (content != NULL)
9938 xmlFree(content);
9939 break;
9940 }
9941 case XML_RELAXNG_VALUE:{
9942 xmlChar *content = NULL;
9943 xmlChar *oldvalue;
9944 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009945
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009946 child = node;
9947 while (child != NULL) {
9948 if (child->type == XML_ELEMENT_NODE) {
9949 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9950 node->parent->name);
9951 ret = -1;
9952 break;
9953 } else if ((child->type == XML_TEXT_NODE) ||
9954 (child->type == XML_CDATA_SECTION_NODE)) {
9955 content = xmlStrcat(content, child->content);
9956 }
9957 /* TODO: handle entities ... */
9958 child = child->next;
9959 }
9960 if (ret == -1) {
9961 if (content != NULL)
9962 xmlFree(content);
9963 break;
9964 }
9965 if (content == NULL) {
9966 content = xmlStrdup(BAD_CAST "");
9967 if (content == NULL) {
9968 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9969 ret = -1;
9970 break;
9971 }
9972 }
9973 oldvalue = ctxt->state->value;
9974 ctxt->state->value = content;
9975 ret = xmlRelaxNGValidateValue(ctxt, define);
9976 ctxt->state->value = oldvalue;
9977 if (ret == -1) {
9978 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9979 } else if (ret == 0) {
9980 ctxt->state->seq = NULL;
9981 }
9982 if (content != NULL)
9983 xmlFree(content);
9984 break;
9985 }
9986 case XML_RELAXNG_LIST:{
9987 xmlChar *content;
9988 xmlNodePtr child;
9989 xmlChar *oldvalue, *oldendvalue;
9990 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009991
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009992 /*
9993 * Make sure it's only text nodes
9994 */
9995
9996 content = NULL;
9997 child = node;
9998 while (child != NULL) {
9999 if (child->type == XML_ELEMENT_NODE) {
10000 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10001 node->parent->name);
10002 ret = -1;
10003 break;
10004 } else if ((child->type == XML_TEXT_NODE) ||
10005 (child->type == XML_CDATA_SECTION_NODE)) {
10006 content = xmlStrcat(content, child->content);
10007 }
10008 /* TODO: handle entities ... */
10009 child = child->next;
10010 }
10011 if (ret == -1) {
10012 if (content != NULL)
10013 xmlFree(content);
10014 break;
10015 }
10016 if (content == NULL) {
10017 content = xmlStrdup(BAD_CAST "");
10018 if (content == NULL) {
10019 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
10020 ret = -1;
10021 break;
10022 }
10023 }
10024 len = xmlStrlen(content);
10025 oldvalue = ctxt->state->value;
10026 oldendvalue = ctxt->state->endvalue;
10027 ctxt->state->value = content;
10028 ctxt->state->endvalue = content + len;
10029 ret = xmlRelaxNGValidateValue(ctxt, define);
10030 ctxt->state->value = oldvalue;
10031 ctxt->state->endvalue = oldendvalue;
10032 if (ret == -1) {
10033 VALID_ERR(XML_RELAXNG_ERR_LIST);
10034 } else if ((ret == 0) && (node != NULL)) {
10035 ctxt->state->seq = node->next;
10036 }
10037 if (content != NULL)
10038 xmlFree(content);
10039 break;
10040 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010041 case XML_RELAXNG_EXCEPT:
10042 case XML_RELAXNG_PARAM:
10043 TODO ret = -1;
10044 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010045 }
10046 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010047#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010048 for (i = 0; i < ctxt->depth; i++)
10049 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010050 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010051 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010052 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010053 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010054 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010055 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010056 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010057 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010058#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010059 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010060}
10061
10062/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010063 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010064 * @ctxt: a Relax-NG validation context
10065 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010066 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010067 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010068 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010069 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010070 */
10071static int
Daniel Veillardfd573f12003-03-16 17:52:32 +000010072xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10073 xmlRelaxNGDefinePtr define) {
10074 xmlRelaxNGStatesPtr states, res;
10075 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010076
Daniel Veillardfd573f12003-03-16 17:52:32 +000010077 /*
10078 * We should NOT have both ctxt->state and ctxt->states
10079 */
10080 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10081 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010082 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010083 ctxt->state = NULL;
10084 }
10085
10086 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10087 if (ctxt->states != NULL) {
10088 ctxt->state = ctxt->states->tabState[0];
10089 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10090 ctxt->states = NULL;
10091 }
10092 ret = xmlRelaxNGValidateState(ctxt, define);
10093 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10094 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010095 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010096 ctxt->state = NULL;
10097 }
10098 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10099 ctxt->state = ctxt->states->tabState[0];
10100 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10101 ctxt->states = NULL;
10102 }
10103 return(ret);
10104 }
10105
10106 states = ctxt->states;
10107 ctxt->states = NULL;
10108 res = NULL;
10109 j = 0;
10110 oldflags = ctxt->flags;
10111 ctxt->flags |= FLAGS_IGNORABLE;
10112 for (i = 0;i < states->nbState;i++) {
10113 ctxt->state = states->tabState[i];
10114 ctxt->states = NULL;
10115 ret = xmlRelaxNGValidateState(ctxt, define);
10116 /*
10117 * We should NOT have both ctxt->state and ctxt->states
10118 */
10119 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10120 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010121 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010122 ctxt->state = NULL;
10123 }
10124 if (ret == 0) {
10125 if (ctxt->states == NULL) {
10126 if (res != NULL) {
10127 /* add the state to the container */
10128 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10129 ctxt->state = NULL;
10130 } else {
10131 /* add the state directly in states */
10132 states->tabState[j++] = ctxt->state;
10133 ctxt->state = NULL;
10134 }
10135 } else {
10136 if (res == NULL) {
10137 /* make it the new container and copy other results */
10138 res = ctxt->states;
10139 ctxt->states = NULL;
10140 for (k = 0;k < j;k++)
10141 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
10142 } else {
10143 /* add all the new results to res and reff the container */
10144 for (k = 0;k < ctxt->states->nbState;k++)
10145 xmlRelaxNGAddStates(ctxt, res,
10146 ctxt->states->tabState[k]);
10147 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10148 ctxt->states = NULL;
10149 }
10150 }
10151 } else {
10152 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010153 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010154 ctxt->state = NULL;
10155 } else if (ctxt->states != NULL) {
10156 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +000010157 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010158 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10159 ctxt->states = NULL;
10160 }
10161 }
10162 }
10163 ctxt->flags = oldflags;
10164 if (res != NULL) {
10165 xmlRelaxNGFreeStates(ctxt, states);
10166 ctxt->states = res;
10167 ret = 0;
10168 } else if (j > 1) {
10169 states->nbState = j;
10170 ctxt->states = states;
10171 ret =0;
10172 } else if (j == 1) {
10173 ctxt->state = states->tabState[0];
10174 xmlRelaxNGFreeStates(ctxt, states);
10175 ret = 0;
10176 } else {
10177 ret = -1;
10178 xmlRelaxNGFreeStates(ctxt, states);
10179 if (ctxt->states != NULL) {
10180 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10181 ctxt->states = NULL;
10182 }
10183 }
10184 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10185 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010186 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010187 ctxt->state = NULL;
10188 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010189 return(ret);
10190}
10191
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010192/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010193 * xmlRelaxNGValidateDocument:
10194 * @ctxt: a Relax-NG validation context
10195 * @doc: the document
10196 *
10197 * Validate the given document
10198 *
10199 * Returns 0 if the validation succeeded or an error code.
10200 */
10201static int
10202xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10203 int ret;
10204 xmlRelaxNGPtr schema;
10205 xmlRelaxNGGrammarPtr grammar;
10206 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010207 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010208
10209 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10210 return(-1);
10211
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010212 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010213 schema = ctxt->schema;
10214 grammar = schema->topgrammar;
10215 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +000010216 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010217 return(-1);
10218 }
10219 state = xmlRelaxNGNewValidState(ctxt, NULL);
10220 ctxt->state = state;
10221 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010222 if ((ctxt->state != NULL) && (state->seq != NULL)) {
10223 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010224 node = state->seq;
10225 node = xmlRelaxNGSkipIgnored(ctxt, node);
10226 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +000010227 if (ret != -1) {
10228 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10229 ret = -1;
10230 }
10231 }
10232 } else if (ctxt->states != NULL) {
10233 int i;
10234 int tmp = -1;
10235
10236 for (i = 0;i < ctxt->states->nbState;i++) {
10237 state = ctxt->states->tabState[i];
10238 node = state->seq;
10239 node = xmlRelaxNGSkipIgnored(ctxt, node);
10240 if (node == NULL)
10241 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +000010242 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010243 }
10244 if (tmp == -1) {
10245 if (ret != -1) {
10246 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10247 ret = -1;
10248 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010249 }
10250 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010251 if (ctxt->state != NULL) {
10252 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10253 ctxt->state = NULL;
10254 }
Daniel Veillard580ced82003-03-21 21:22:48 +000010255 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +000010256 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010257#ifdef DEBUG
10258 else if (ctxt->errNr != 0) {
10259 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
10260 ctxt->errNr);
10261 xmlRelaxNGDumpValidError(ctxt);
10262 }
10263#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010264 if (ctxt->idref == 1) {
10265 xmlValidCtxt vctxt;
10266
10267 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10268 vctxt.valid = 1;
10269 vctxt.error = ctxt->error;
10270 vctxt.warning = ctxt->warning;
10271 vctxt.userData = ctxt->userData;
10272
10273 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10274 ret = -1;
10275 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010276 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10277 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010278
10279 return(ret);
10280}
10281
Daniel Veillardfd573f12003-03-16 17:52:32 +000010282/************************************************************************
10283 * *
10284 * Validation interfaces *
10285 * *
10286 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +000010287/**
10288 * xmlRelaxNGNewValidCtxt:
10289 * @schema: a precompiled XML RelaxNGs
10290 *
10291 * Create an XML RelaxNGs validation context based on the given schema
10292 *
10293 * Returns the validation context or NULL in case of error
10294 */
10295xmlRelaxNGValidCtxtPtr
10296xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
10297 xmlRelaxNGValidCtxtPtr ret;
10298
10299 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10300 if (ret == NULL) {
10301 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +000010302 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010303 return (NULL);
10304 }
10305 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10306 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010307 ret->error = xmlGenericError;
10308 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010309 ret->errNr = 0;
10310 ret->errMax = 0;
10311 ret->err = NULL;
10312 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010313 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010314 ret->states = NULL;
10315 ret->freeState = NULL;
10316 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010317 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010318 return (ret);
10319}
10320
10321/**
10322 * xmlRelaxNGFreeValidCtxt:
10323 * @ctxt: the schema validation context
10324 *
10325 * Free the resources associated to the schema validation context
10326 */
10327void
10328xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010329 int k;
10330
Daniel Veillard6eadf632003-01-23 18:29:16 +000010331 if (ctxt == NULL)
10332 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010333 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +000010334 xmlRelaxNGFreeStates(NULL, ctxt->states);
10335 if (ctxt->freeState != NULL) {
10336 for (k = 0;k < ctxt->freeState->nbState;k++) {
10337 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10338 }
10339 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10340 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010341 if (ctxt->freeStates != NULL) {
10342 for (k = 0;k < ctxt->freeStatesNr;k++) {
10343 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10344 }
10345 xmlFree(ctxt->freeStates);
10346 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010347 if (ctxt->errTab != NULL)
10348 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010349 if (ctxt->elemTab != NULL) {
10350 xmlRegExecCtxtPtr exec;
10351
10352 exec = xmlRelaxNGElemPop(ctxt);
10353 while (exec != NULL) {
10354 xmlRegFreeExecCtxt(exec);
10355 exec = xmlRelaxNGElemPop(ctxt);
10356 }
10357 xmlFree(ctxt->elemTab);
10358 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010359 xmlFree(ctxt);
10360}
10361
10362/**
10363 * xmlRelaxNGSetValidErrors:
10364 * @ctxt: a Relax-NG validation context
10365 * @err: the error function
10366 * @warn: the warning function
10367 * @ctx: the functions context
10368 *
10369 * Set the error and warning callback informations
10370 */
10371void
10372xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10373 xmlRelaxNGValidityErrorFunc err,
10374 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
10375 if (ctxt == NULL)
10376 return;
10377 ctxt->error = err;
10378 ctxt->warning = warn;
10379 ctxt->userData = ctx;
10380}
10381
10382/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010383 * xmlRelaxNGGetValidErrors:
10384 * @ctxt: a Relax-NG validation context
10385 * @err: the error function result
10386 * @warn: the warning function result
10387 * @ctx: the functions context result
10388 *
10389 * Get the error and warning callback informations
10390 *
10391 * Returns -1 in case of error and 0 otherwise
10392 */
10393int
10394xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10395 xmlRelaxNGValidityErrorFunc *err,
10396 xmlRelaxNGValidityWarningFunc *warn, void **ctx) {
10397 if (ctxt == NULL)
10398 return(-1);
10399 if (err != NULL) *err = ctxt->error;
10400 if (warn != NULL) *warn = ctxt->warning;
10401 if (ctx != NULL) *ctx = ctxt->userData;
10402 return(0);
10403}
10404
10405/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010406 * xmlRelaxNGValidateDoc:
10407 * @ctxt: a Relax-NG validation context
10408 * @doc: a parsed document tree
10409 *
10410 * Validate a document tree in memory.
10411 *
10412 * Returns 0 if the document is valid, a positive error code
10413 * number otherwise and -1 in case of internal or API error.
10414 */
10415int
10416xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10417 int ret;
10418
10419 if ((ctxt == NULL) || (doc == NULL))
10420 return(-1);
10421
10422 ctxt->doc = doc;
10423
10424 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010425 /*
10426 * TODO: build error codes
10427 */
10428 if (ret == -1)
10429 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010430 return(ret);
10431}
10432
10433#endif /* LIBXML_SCHEMAS_ENABLED */
10434