blob: 054277c0d19286187ac39a9595e7bca6b1decfc2 [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;
1079 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001080 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001081 if (nbAttrs < MAX_ATTR) {
1082 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1083 } else {
1084 attr = node->properties;
1085 nbAttrs = 0;
1086 while (attr != NULL) {
1087 ret->attrs[nbAttrs++] = attr;
1088 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001089 }
1090 }
1091 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001092 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001093 return (ret);
1094}
1095
1096/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001097 * xmlRelaxNGCopyValidState:
1098 * @ctxt: a Relax-NG validation context
1099 * @state: a validation state
1100 *
1101 * Copy the validation state
1102 *
1103 * Returns the newly allocated structure or NULL in case or error
1104 */
1105static xmlRelaxNGValidStatePtr
1106xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1107 xmlRelaxNGValidStatePtr state)
1108{
1109 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001110 unsigned int maxAttrs;
1111 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001112
1113 if (state == NULL)
1114 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001115 if ((ctxt->freeState != NULL) &&
1116 (ctxt->freeState->nbState > 0)) {
1117 ctxt->freeState->nbState--;
1118 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1119 } else {
1120 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1121 if (ret == NULL) {
1122 if ((ctxt != NULL) && (ctxt->error != NULL))
1123 ctxt->error(ctxt->userData, "Out of memory\n");
1124 return (NULL);
1125 }
1126 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001127 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001128 attrs = ret->attrs;
1129 maxAttrs = ret->maxAttrs;
1130 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1131 ret->attrs = attrs;
1132 ret->maxAttrs = maxAttrs;
1133 if (state->nbAttrs > 0) {
1134 if (ret->attrs == NULL) {
1135 ret->maxAttrs = state->maxAttrs;
1136 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1137 sizeof(xmlAttrPtr));
1138 if (ret->attrs == NULL) {
1139 if ((ctxt != NULL) && (ctxt->error != NULL))
1140 ctxt->error(ctxt->userData, "Out of memory\n");
1141 ret->nbAttrs = 0;
1142 return (ret);
1143 }
1144 } else if (ret->maxAttrs < state->nbAttrs) {
1145 xmlAttrPtr *tmp;
1146
1147 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1148 sizeof(xmlAttrPtr));
1149 if (tmp == NULL) {
1150 if ((ctxt != NULL) && (ctxt->error != NULL))
1151 ctxt->error(ctxt->userData, "Out of memory\n");
1152 ret->nbAttrs = 0;
1153 return (ret);
1154 }
1155 ret->maxAttrs = state->maxAttrs;
1156 }
1157 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1158 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001159 return(ret);
1160}
1161
1162/**
1163 * xmlRelaxNGEqualValidState:
1164 * @ctxt: a Relax-NG validation context
1165 * @state1: a validation state
1166 * @state2: a validation state
1167 *
1168 * Compare the validation states for equality
1169 *
1170 * Returns 1 if equald, 0 otherwise
1171 */
1172static int
1173xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1174 xmlRelaxNGValidStatePtr state1,
1175 xmlRelaxNGValidStatePtr state2)
1176{
1177 int i;
1178
1179 if ((state1 == NULL) || (state2 == NULL))
1180 return(0);
1181 if (state1 == state2)
1182 return(1);
1183 if (state1->node != state2->node)
1184 return(0);
1185 if (state1->seq != state2->seq)
1186 return(0);
1187 if (state1->nbAttrLeft != state2->nbAttrLeft)
1188 return(0);
1189 if (state1->nbAttrs != state2->nbAttrs)
1190 return(0);
1191 if (state1->endvalue != state2->endvalue)
1192 return(0);
1193 if ((state1->value != state2->value) &&
1194 (!xmlStrEqual(state1->value, state2->value)))
1195 return(0);
1196 for (i = 0;i < state1->nbAttrs;i++) {
1197 if (state1->attrs[i] != state2->attrs[i])
1198 return(0);
1199 }
1200 return(1);
1201}
1202
1203/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001204 * xmlRelaxNGFreeValidState:
1205 * @state: a validation state structure
1206 *
1207 * Deallocate a RelaxNG validation state structure.
1208 */
1209static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001210xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1211 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001212{
1213 if (state == NULL)
1214 return;
1215
Daniel Veillard798024a2003-03-19 10:36:09 +00001216 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1217 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1218 }
1219 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1220 if (state->attrs != NULL)
1221 xmlFree(state->attrs);
1222 xmlFree(state);
1223 } else {
1224 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1225 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001226}
1227
1228/************************************************************************
1229 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001230 * Document functions *
1231 * *
1232 ************************************************************************/
1233static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1234 xmlDocPtr doc);
1235
1236/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001237 * xmlRelaxNGIncludePush:
1238 * @ctxt: the parser context
1239 * @value: the element doc
1240 *
1241 * Pushes a new include on top of the include stack
1242 *
1243 * Returns 0 in case of error, the index in the stack otherwise
1244 */
1245static int
1246xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1247 xmlRelaxNGIncludePtr value)
1248{
1249 if (ctxt->incTab == NULL) {
1250 ctxt->incMax = 4;
1251 ctxt->incNr = 0;
1252 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1253 ctxt->incMax * sizeof(ctxt->incTab[0]));
1254 if (ctxt->incTab == NULL) {
1255 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1256 return (0);
1257 }
1258 }
1259 if (ctxt->incNr >= ctxt->incMax) {
1260 ctxt->incMax *= 2;
1261 ctxt->incTab =
1262 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1263 ctxt->incMax *
1264 sizeof(ctxt->incTab[0]));
1265 if (ctxt->incTab == NULL) {
1266 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1267 return (0);
1268 }
1269 }
1270 ctxt->incTab[ctxt->incNr] = value;
1271 ctxt->inc = value;
1272 return (ctxt->incNr++);
1273}
1274
1275/**
1276 * xmlRelaxNGIncludePop:
1277 * @ctxt: the parser context
1278 *
1279 * Pops the top include from the include stack
1280 *
1281 * Returns the include just removed
1282 */
1283static xmlRelaxNGIncludePtr
1284xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1285{
1286 xmlRelaxNGIncludePtr ret;
1287
1288 if (ctxt->incNr <= 0)
1289 return (0);
1290 ctxt->incNr--;
1291 if (ctxt->incNr > 0)
1292 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1293 else
1294 ctxt->inc = NULL;
1295 ret = ctxt->incTab[ctxt->incNr];
1296 ctxt->incTab[ctxt->incNr] = 0;
1297 return (ret);
1298}
1299
1300/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001301 * xmlRelaxNGRemoveRedefine:
1302 * @ctxt: the parser context
1303 * @URL: the normalized URL
1304 * @target: the included target
1305 * @name: the define name to eliminate
1306 *
1307 * Applies the elimination algorithm of 4.7
1308 *
1309 * Returns 0 in case of error, 1 in case of success.
1310 */
1311static int
1312xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1313 const xmlChar *URL ATTRIBUTE_UNUSED,
1314 xmlNodePtr target, const xmlChar *name) {
1315 int found = 0;
1316 xmlNodePtr tmp, tmp2;
1317 xmlChar *name2;
1318
1319#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001320 if (name == NULL)
1321 xmlGenericError(xmlGenericErrorContext,
1322 "Elimination of <include> start from %s\n", URL);
1323 else
1324 xmlGenericError(xmlGenericErrorContext,
1325 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001326#endif
1327 tmp = target;
1328 while (tmp != NULL) {
1329 tmp2 = tmp->next;
1330 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1331 found = 1;
1332 xmlUnlinkNode(tmp);
1333 xmlFreeNode(tmp);
1334 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1335 name2 = xmlGetProp(tmp, BAD_CAST "name");
1336 xmlRelaxNGNormExtSpace(name2);
1337 if (name2 != NULL) {
1338 if (xmlStrEqual(name, name2)) {
1339 found = 1;
1340 xmlUnlinkNode(tmp);
1341 xmlFreeNode(tmp);
1342 }
1343 xmlFree(name2);
1344 }
1345 } else if (IS_RELAXNG(tmp, "include")) {
1346 xmlChar *href = NULL;
1347 xmlRelaxNGDocumentPtr inc = tmp->_private;
1348
1349 if ((inc != NULL) && (inc->doc != NULL) &&
1350 (inc->doc->children != NULL)) {
1351
1352 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1353#ifdef DEBUG_INCLUDE
1354 href = xmlGetProp(tmp, BAD_CAST "href");
1355#endif
1356 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1357 inc->doc->children->children, name) == 1) {
1358 found = 1;
1359 }
1360 if (href != NULL)
1361 xmlFree(href);
1362 }
1363 }
1364 }
1365 tmp = tmp2;
1366 }
1367 return(found);
1368}
1369
1370/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001371 * xmlRelaxNGLoadInclude:
1372 * @ctxt: the parser context
1373 * @URL: the normalized URL
1374 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001375 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001376 *
1377 * First lookup if the document is already loaded into the parser context,
1378 * check against recursion. If not found the resource is loaded and
1379 * the content is preprocessed before being returned back to the caller.
1380 *
1381 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1382 */
1383static xmlRelaxNGIncludePtr
1384xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001385 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001386 xmlRelaxNGIncludePtr ret = NULL;
1387 xmlDocPtr doc;
1388 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001389 xmlNodePtr root, cur;
1390
1391#ifdef DEBUG_INCLUDE
1392 xmlGenericError(xmlGenericErrorContext,
1393 "xmlRelaxNGLoadInclude(%s)\n", URL);
1394#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001395
1396 /*
1397 * check against recursion in the stack
1398 */
1399 for (i = 0;i < ctxt->incNr;i++) {
1400 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1401 if (ctxt->error != NULL)
1402 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001403 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001404 URL);
1405 ctxt->nbErrors++;
1406 return(NULL);
1407 }
1408 }
1409
1410 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001411 * load the document
1412 */
1413 doc = xmlParseFile((const char *) URL);
1414 if (doc == NULL) {
1415 if (ctxt->error != NULL)
1416 ctxt->error(ctxt->userData,
1417 "xmlRelaxNG: could not load %s\n", URL);
1418 ctxt->nbErrors++;
1419 return (NULL);
1420 }
1421
Daniel Veillard5add8682003-03-10 13:13:58 +00001422#ifdef DEBUG_INCLUDE
1423 xmlGenericError(xmlGenericErrorContext,
1424 "Parsed %s Okay\n", URL);
1425#endif
1426
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 /*
1428 * Allocate the document structures and register it first.
1429 */
1430 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1431 if (ret == NULL) {
1432 if (ctxt->error != NULL)
1433 ctxt->error(ctxt->userData,
1434 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1435 ctxt->nbErrors++;
1436 xmlFreeDoc(doc);
1437 return (NULL);
1438 }
1439 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1440 ret->doc = doc;
1441 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001442 ret->next = ctxt->includes;
1443 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001444
1445 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001446 * transmit the ns if needed
1447 */
1448 if (ns != NULL) {
1449 root = xmlDocGetRootElement(doc);
1450 if (root != NULL) {
1451 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1452 xmlSetProp(root, BAD_CAST"ns", ns);
1453 }
1454 }
1455 }
1456
1457 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001458 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001459 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001460 xmlRelaxNGIncludePush(ctxt, ret);
1461
1462 /*
1463 * Some preprocessing of the document content, this include recursing
1464 * in the include stack.
1465 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001466#ifdef DEBUG_INCLUDE
1467 xmlGenericError(xmlGenericErrorContext,
1468 "cleanup of %s\n", URL);
1469#endif
1470
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001471 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1472 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001473 ctxt->inc = NULL;
1474 return(NULL);
1475 }
1476
1477 /*
1478 * Pop up the include from the stack
1479 */
1480 xmlRelaxNGIncludePop(ctxt);
1481
Daniel Veillard5add8682003-03-10 13:13:58 +00001482#ifdef DEBUG_INCLUDE
1483 xmlGenericError(xmlGenericErrorContext,
1484 "Checking of %s\n", URL);
1485#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001486 /*
1487 * Check that the top element is a grammar
1488 */
1489 root = xmlDocGetRootElement(doc);
1490 if (root == NULL) {
1491 if (ctxt->error != NULL)
1492 ctxt->error(ctxt->userData,
1493 "xmlRelaxNG: included document is empty %s\n", URL);
1494 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001495 return (NULL);
1496 }
1497 if (!IS_RELAXNG(root, "grammar")) {
1498 if (ctxt->error != NULL)
1499 ctxt->error(ctxt->userData,
1500 "xmlRelaxNG: included document %s root is not a grammar\n",
1501 URL);
1502 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001503 return (NULL);
1504 }
1505
1506 /*
1507 * Elimination of redefined rules in the include.
1508 */
1509 cur = node->children;
1510 while (cur != NULL) {
1511 if (IS_RELAXNG(cur, "start")) {
1512 int found = 0;
1513
Daniel Veillard5add8682003-03-10 13:13:58 +00001514 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001515 if (!found) {
1516 if (ctxt->error != NULL)
1517 ctxt->error(ctxt->userData,
1518 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1519 URL);
1520 ctxt->nbErrors++;
1521 }
1522 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001523 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001524
1525 name = xmlGetProp(cur, BAD_CAST "name");
1526 if (name == NULL) {
1527 if (ctxt->error != NULL)
1528 ctxt->error(ctxt->userData,
1529 "xmlRelaxNG: include %s has define without name\n",
1530 URL);
1531 ctxt->nbErrors++;
1532 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001533 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001534
Daniel Veillardd2298792003-02-14 16:54:11 +00001535 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001536 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1537 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001538 if (!found) {
1539 if (ctxt->error != NULL)
1540 ctxt->error(ctxt->userData,
1541 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1542 URL, name);
1543 ctxt->nbErrors++;
1544 }
1545 xmlFree(name);
1546 }
1547 }
1548 cur = cur->next;
1549 }
1550
1551
1552 return(ret);
1553}
1554
1555/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001556 * xmlRelaxNGValidErrorPush:
1557 * @ctxt: the validation context
1558 * @err: the error code
1559 * @arg1: the first string argument
1560 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001561 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001562 *
1563 * Pushes a new error on top of the error stack
1564 *
1565 * Returns 0 in case of error, the index in the stack otherwise
1566 */
1567static int
1568xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001569 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001570{
1571 xmlRelaxNGValidErrorPtr cur;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001572#ifdef DEBUG_ERROR
1573 xmlGenericError(xmlGenericErrorContext,
1574 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1575#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001576 if (ctxt->errTab == NULL) {
1577 ctxt->errMax = 8;
1578 ctxt->errNr = 0;
1579 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1580 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1581 if (ctxt->errTab == NULL) {
1582 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1583 return (0);
1584 }
Daniel Veillard20863822003-03-22 17:51:47 +00001585 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001586 }
1587 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001588 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001589 ctxt->errTab =
1590 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001591 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001592 if (ctxt->errTab == NULL) {
1593 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1594 return (0);
1595 }
Daniel Veillard20863822003-03-22 17:51:47 +00001596 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001597 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001598 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001599 (ctxt->err->node == ctxt->state->node) &&
1600 (ctxt->err->err == err))
1601 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001602 cur = &ctxt->errTab[ctxt->errNr];
1603 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001604 if (dup) {
1605 cur->arg1 = xmlStrdup(arg1);
1606 cur->arg2 = xmlStrdup(arg2);
1607 cur->flags = ERROR_IS_DUP;
1608 } else {
1609 cur->arg1 = arg1;
1610 cur->arg2 = arg2;
1611 cur->flags = 0;
1612 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001613 if (ctxt->state != NULL) {
1614 cur->node = ctxt->state->node;
1615 cur->seq = ctxt->state->seq;
1616 } else {
1617 cur->node = NULL;
1618 cur->seq = NULL;
1619 }
1620 ctxt->err = cur;
1621 return (ctxt->errNr++);
1622}
1623
1624/**
1625 * xmlRelaxNGValidErrorPop:
1626 * @ctxt: the validation context
1627 *
1628 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001629 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001630static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001631xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1632{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001633 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001634
Daniel Veillard580ced82003-03-21 21:22:48 +00001635 if (ctxt->errNr <= 0) {
1636 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001637 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001638 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001639 ctxt->errNr--;
1640 if (ctxt->errNr > 0)
1641 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1642 else
1643 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001644 cur = &ctxt->errTab[ctxt->errNr];
1645 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001646 if (cur->arg1 != NULL)
1647 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001648 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001649 if (cur->arg2 != NULL)
1650 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001651 cur->arg2 = NULL;
1652 cur->flags = 0;
1653 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001654}
1655
Daniel Veillard42f12e92003-03-07 18:32:59 +00001656/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001657 * xmlRelaxNGDocumentPush:
1658 * @ctxt: the parser context
1659 * @value: the element doc
1660 *
1661 * Pushes a new doc on top of the doc stack
1662 *
1663 * Returns 0 in case of error, the index in the stack otherwise
1664 */
1665static int
1666xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1667 xmlRelaxNGDocumentPtr value)
1668{
1669 if (ctxt->docTab == NULL) {
1670 ctxt->docMax = 4;
1671 ctxt->docNr = 0;
1672 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1673 ctxt->docMax * sizeof(ctxt->docTab[0]));
1674 if (ctxt->docTab == NULL) {
1675 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1676 return (0);
1677 }
1678 }
1679 if (ctxt->docNr >= ctxt->docMax) {
1680 ctxt->docMax *= 2;
1681 ctxt->docTab =
1682 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1683 ctxt->docMax *
1684 sizeof(ctxt->docTab[0]));
1685 if (ctxt->docTab == NULL) {
1686 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1687 return (0);
1688 }
1689 }
1690 ctxt->docTab[ctxt->docNr] = value;
1691 ctxt->doc = value;
1692 return (ctxt->docNr++);
1693}
1694
1695/**
1696 * xmlRelaxNGDocumentPop:
1697 * @ctxt: the parser context
1698 *
1699 * Pops the top doc from the doc stack
1700 *
1701 * Returns the doc just removed
1702 */
1703static xmlRelaxNGDocumentPtr
1704xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1705{
1706 xmlRelaxNGDocumentPtr ret;
1707
1708 if (ctxt->docNr <= 0)
1709 return (0);
1710 ctxt->docNr--;
1711 if (ctxt->docNr > 0)
1712 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1713 else
1714 ctxt->doc = NULL;
1715 ret = ctxt->docTab[ctxt->docNr];
1716 ctxt->docTab[ctxt->docNr] = 0;
1717 return (ret);
1718}
1719
1720/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001721 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001722 * @ctxt: the parser context
1723 * @URL: the normalized URL
1724 * @ns: the inherited ns if any
1725 *
1726 * First lookup if the document is already loaded into the parser context,
1727 * check against recursion. If not found the resource is loaded and
1728 * the content is preprocessed before being returned back to the caller.
1729 *
1730 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1731 */
1732static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001733xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001734 const xmlChar *ns) {
1735 xmlRelaxNGDocumentPtr ret = NULL;
1736 xmlDocPtr doc;
1737 xmlNodePtr root;
1738 int i;
1739
1740 /*
1741 * check against recursion in the stack
1742 */
1743 for (i = 0;i < ctxt->docNr;i++) {
1744 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1745 if (ctxt->error != NULL)
1746 ctxt->error(ctxt->userData,
1747 "Detected an externalRef recursion for %s\n",
1748 URL);
1749 ctxt->nbErrors++;
1750 return(NULL);
1751 }
1752 }
1753
1754 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001755 * load the document
1756 */
1757 doc = xmlParseFile((const char *) URL);
1758 if (doc == NULL) {
1759 if (ctxt->error != NULL)
1760 ctxt->error(ctxt->userData,
1761 "xmlRelaxNG: could not load %s\n", URL);
1762 ctxt->nbErrors++;
1763 return (NULL);
1764 }
1765
1766 /*
1767 * Allocate the document structures and register it first.
1768 */
1769 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1770 if (ret == NULL) {
1771 if (ctxt->error != NULL)
1772 ctxt->error(ctxt->userData,
1773 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1774 ctxt->nbErrors++;
1775 xmlFreeDoc(doc);
1776 return (NULL);
1777 }
1778 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1779 ret->doc = doc;
1780 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001781 ret->next = ctxt->documents;
1782 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001783
1784 /*
1785 * transmit the ns if needed
1786 */
1787 if (ns != NULL) {
1788 root = xmlDocGetRootElement(doc);
1789 if (root != NULL) {
1790 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1791 xmlSetProp(root, BAD_CAST"ns", ns);
1792 }
1793 }
1794 }
1795
1796 /*
1797 * push it on the stack and register it in the hash table
1798 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001799 xmlRelaxNGDocumentPush(ctxt, ret);
1800
1801 /*
1802 * Some preprocessing of the document content
1803 */
1804 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1805 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001806 ctxt->doc = NULL;
1807 return(NULL);
1808 }
1809
1810 xmlRelaxNGDocumentPop(ctxt);
1811
1812 return(ret);
1813}
1814
1815/************************************************************************
1816 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001817 * Error functions *
1818 * *
1819 ************************************************************************/
1820
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001821#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1822#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1823#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1824#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1825#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001826
Daniel Veillard231d7912003-02-09 14:22:17 +00001827static const char *
1828xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1829 if (def == NULL)
1830 return("none");
1831 switch(def->type) {
1832 case XML_RELAXNG_EMPTY: return("empty");
1833 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1834 case XML_RELAXNG_EXCEPT: return("except");
1835 case XML_RELAXNG_TEXT: return("text");
1836 case XML_RELAXNG_ELEMENT: return("element");
1837 case XML_RELAXNG_DATATYPE: return("datatype");
1838 case XML_RELAXNG_VALUE: return("value");
1839 case XML_RELAXNG_LIST: return("list");
1840 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1841 case XML_RELAXNG_DEF: return("def");
1842 case XML_RELAXNG_REF: return("ref");
1843 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1844 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001845 case XML_RELAXNG_OPTIONAL: return("optional");
1846 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001847 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1848 case XML_RELAXNG_CHOICE: return("choice");
1849 case XML_RELAXNG_GROUP: return("group");
1850 case XML_RELAXNG_INTERLEAVE: return("interleave");
1851 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001852 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001853 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001854 }
1855 return("unknown");
1856}
Daniel Veillardd2298792003-02-14 16:54:11 +00001857
Daniel Veillard6eadf632003-01-23 18:29:16 +00001858/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001859 * xmlRelaxNGGetErrorString:
1860 * @err: the error code
1861 * @arg1: the first string argument
1862 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001863 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001864 * computes a formatted error string for the given error code and args
1865 *
1866 * Returns the error string, it must be deallocated by the caller
1867 */
1868static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001869xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1870 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001871 char msg[1000];
1872
1873 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001874 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001875 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001876 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001877
1878 msg[0] = 0;
1879 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001880 case XML_RELAXNG_OK:
1881 return(NULL);
1882 case XML_RELAXNG_ERR_MEMORY:
1883 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001884 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001885 snprintf(msg, 1000, "failed to validate type %s", arg1);
1886 break;
1887 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001888 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001889 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001890 case XML_RELAXNG_ERR_DUPID:
1891 snprintf(msg, 1000, "ID %s redefined", arg1);
1892 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001893 case XML_RELAXNG_ERR_TYPECMP:
1894 snprintf(msg, 1000, "failed to compare type %s", arg1);
1895 break;
1896 case XML_RELAXNG_ERR_NOSTATE:
1897 return(xmlCharStrdup("Internal error: no state"));
1898 case XML_RELAXNG_ERR_NODEFINE:
1899 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001900 case XML_RELAXNG_ERR_INTERNAL:
1901 snprintf(msg, 1000, "Internal error: %s", arg1);
1902 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001903 case XML_RELAXNG_ERR_LISTEXTRA:
1904 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1905 break;
1906 case XML_RELAXNG_ERR_INTERNODATA:
1907 return(xmlCharStrdup("Internal: interleave block has no data"));
1908 case XML_RELAXNG_ERR_INTERSEQ:
1909 return(xmlCharStrdup("Invalid sequence in interleave"));
1910 case XML_RELAXNG_ERR_INTEREXTRA:
1911 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1912 break;
1913 case XML_RELAXNG_ERR_ELEMNAME:
1914 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1915 break;
1916 case XML_RELAXNG_ERR_ELEMNONS:
1917 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1918 break;
1919 case XML_RELAXNG_ERR_ELEMWRONGNS:
1920 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1921 arg1, arg2);
1922 break;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00001923 case XML_RELAXNG_ERR_ELEMWRONG:
1924 snprintf(msg, 1000, "Did not expect element %s there",
1925 arg1);
1926 break;
1927 case XML_RELAXNG_ERR_TEXTWRONG:
1928 snprintf(msg, 1000, "Did not expect text in element %s content",
1929 arg1);
1930 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001931 case XML_RELAXNG_ERR_ELEMEXTRANS:
1932 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1933 break;
1934 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1935 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1936 break;
1937 case XML_RELAXNG_ERR_NOELEM:
1938 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1939 break;
1940 case XML_RELAXNG_ERR_NOTELEM:
1941 return(xmlCharStrdup("Expecting an element got text"));
1942 case XML_RELAXNG_ERR_ATTRVALID:
1943 snprintf(msg, 1000, "Element %s failed to validate attributes",
1944 arg1);
1945 break;
1946 case XML_RELAXNG_ERR_CONTENTVALID:
1947 snprintf(msg, 1000, "Element %s failed to validate content",
1948 arg1);
1949 break;
1950 case XML_RELAXNG_ERR_EXTRACONTENT:
1951 snprintf(msg, 1000, "Element %s has extra content: %s",
1952 arg1, arg2);
1953 break;
1954 case XML_RELAXNG_ERR_INVALIDATTR:
1955 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1956 arg1, arg2);
1957 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001958 case XML_RELAXNG_ERR_LACKDATA:
1959 snprintf(msg, 1000, "Datatype element %s contains no data",
1960 arg1);
1961 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001962 case XML_RELAXNG_ERR_DATAELEM:
1963 snprintf(msg, 1000, "Datatype element %s has child elements",
1964 arg1);
1965 break;
1966 case XML_RELAXNG_ERR_VALELEM:
1967 snprintf(msg, 1000, "Value element %s has child elements",
1968 arg1);
1969 break;
1970 case XML_RELAXNG_ERR_LISTELEM:
1971 snprintf(msg, 1000, "List element %s has child elements",
1972 arg1);
1973 break;
1974 case XML_RELAXNG_ERR_DATATYPE:
1975 snprintf(msg, 1000, "Error validating datatype %s",
1976 arg1);
1977 break;
1978 case XML_RELAXNG_ERR_VALUE:
1979 snprintf(msg, 1000, "Error validating value %s",
1980 arg1);
1981 break;
1982 case XML_RELAXNG_ERR_LIST:
1983 return(xmlCharStrdup("Error validating list"));
1984 case XML_RELAXNG_ERR_NOGRAMMAR:
1985 return(xmlCharStrdup("No top grammar defined"));
1986 case XML_RELAXNG_ERR_EXTRADATA:
1987 return(xmlCharStrdup("Extra data in the document"));
1988 default:
Daniel Veillardac297932003-04-17 12:55:35 +00001989 return(xmlCharStrdup("Unknown error !"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001990 }
1991 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001992 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001993 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00001994 msg[1000 - 1] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001995 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001996}
1997
1998/**
1999 * xmlRelaxNGValidErrorContext:
2000 * @ctxt: the validation context
2001 * @node: the node
2002 * @child: the node child generating the problem.
2003 *
2004 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00002005 */
2006static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00002007xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
2008 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00002009{
2010 int line = 0;
2011 const xmlChar *file = NULL;
2012 const xmlChar *name = NULL;
2013 const char *type = "error";
2014
2015 if ((ctxt == NULL) || (ctxt->error == NULL))
2016 return;
2017
2018 if (child != NULL)
2019 node = child;
2020
2021 if (node != NULL) {
2022 if ((node->type == XML_DOCUMENT_NODE) ||
2023 (node->type == XML_HTML_DOCUMENT_NODE)) {
2024 xmlDocPtr doc = (xmlDocPtr) node;
2025
2026 file = doc->URL;
2027 } else {
2028 /*
2029 * Try to find contextual informations to report
2030 */
2031 if (node->type == XML_ELEMENT_NODE) {
Daniel Veillard34ba3872003-07-15 13:34:05 +00002032 line = (long) node->content;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002033 } else if ((node->prev != NULL) &&
2034 (node->prev->type == XML_ELEMENT_NODE)) {
Daniel Veillard34ba3872003-07-15 13:34:05 +00002035 line = (long) node->prev->content;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002036 } else if ((node->parent != NULL) &&
2037 (node->parent->type == XML_ELEMENT_NODE)) {
Daniel Veillard34ba3872003-07-15 13:34:05 +00002038 line = (long) node->parent->content;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002039 }
2040 if ((node->doc != NULL) && (node->doc->URL != NULL))
2041 file = node->doc->URL;
2042 if (node->name != NULL)
2043 name = node->name;
2044 }
2045 }
2046
Daniel Veillard42f12e92003-03-07 18:32:59 +00002047 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002048
2049 if ((file != NULL) && (line != 0) && (name != NULL))
2050 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2051 type, file, line, name);
2052 else if ((file != NULL) && (name != NULL))
2053 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2054 type, file, name);
2055 else if ((file != NULL) && (line != 0))
2056 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2057 else if (file != NULL)
2058 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2059 else if (name != NULL)
2060 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2061 else
2062 ctxt->error(ctxt->userData, "%s\n", type);
2063}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002064
2065/**
2066 * xmlRelaxNGShowValidError:
2067 * @ctxt: the validation context
2068 * @err: the error number
2069 * @node: the node
2070 * @child: the node child generating the problem.
2071 * @arg1: the first argument
2072 * @arg2: the second argument
2073 *
2074 * Show a validation error.
2075 */
2076static void
2077xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2078 xmlNodePtr node, xmlNodePtr child,
2079 const xmlChar *arg1, const xmlChar *arg2)
2080{
2081 xmlChar *msg;
2082
2083 if (ctxt->error == NULL)
2084 return;
2085
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002086#ifdef DEBUG_ERROR
2087 xmlGenericError(xmlGenericErrorContext,
2088 "Show error %d\n", err);
2089#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002090 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2091 if (msg == NULL)
2092 return;
2093
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002094 if (ctxt->errNo == XML_RELAXNG_OK)
2095 ctxt->errNo = err;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002096 xmlRelaxNGValidErrorContext(ctxt, node, child);
2097 ctxt->error(ctxt->userData, "%s\n", msg);
2098 xmlFree(msg);
2099}
2100
2101/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002102 * xmlRelaxNGPopErrors:
2103 * @ctxt: the validation context
2104 * @level: the error level in the stack
2105 *
2106 * pop and discard all errors until the given level is reached
2107 */
2108static void
2109xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2110 int i;
2111 xmlRelaxNGValidErrorPtr err;
2112
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002113#ifdef DEBUG_ERROR
2114 xmlGenericError(xmlGenericErrorContext,
2115 "Pop errors till level %d\n", level);
2116#endif
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002117 for (i = level;i < ctxt->errNr;i++) {
2118 err = &ctxt->errTab[i];
2119 if (err->flags & ERROR_IS_DUP) {
2120 if (err->arg1 != NULL)
2121 xmlFree((xmlChar *)err->arg1);
2122 err->arg1 = NULL;
2123 if (err->arg2 != NULL)
2124 xmlFree((xmlChar *)err->arg2);
2125 err->arg2 = NULL;
2126 err->flags = 0;
2127 }
2128 }
2129 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002130 if (ctxt->errNr <= 0)
2131 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002132}
2133/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002134 * xmlRelaxNGDumpValidError:
2135 * @ctxt: the validation context
2136 *
2137 * Show all validation error over a given index.
2138 */
2139static void
2140xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002141 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002142 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002143
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002144#ifdef DEBUG_ERROR
2145 xmlGenericError(xmlGenericErrorContext,
2146 "Dumping error stack %d errors\n", ctxt->errNr);
2147#endif
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002148 for (i = 0, k = 0;i < ctxt->errNr;i++) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00002149 err = &ctxt->errTab[i];
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002150 if (k < MAX_ERROR) {
2151 for (j = 0;j < i;j++) {
2152 dup = &ctxt->errTab[j];
2153 if ((err->err == dup->err) && (err->node == dup->node) &&
2154 (xmlStrEqual(err->arg1, dup->arg1)) &&
2155 (xmlStrEqual(err->arg2, dup->arg2))) {
2156 goto skip;
2157 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002158 }
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002159 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2160 err->arg1, err->arg2);
2161 k++;
Daniel Veillard580ced82003-03-21 21:22:48 +00002162 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002163skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002164 if (err->flags & ERROR_IS_DUP) {
2165 if (err->arg1 != NULL)
2166 xmlFree((xmlChar *)err->arg1);
2167 err->arg1 = NULL;
2168 if (err->arg2 != NULL)
2169 xmlFree((xmlChar *)err->arg2);
2170 err->arg2 = NULL;
2171 err->flags = 0;
2172 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002173 }
2174 ctxt->errNr = 0;
2175}
2176/**
2177 * xmlRelaxNGAddValidError:
2178 * @ctxt: the validation context
2179 * @err: the error number
2180 * @arg1: the first argument
2181 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002182 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002183 *
2184 * Register a validation error, either generating it if it's sure
2185 * or stacking it for later handling if unsure.
2186 */
2187static void
2188xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002189 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002190{
2191 if ((ctxt == NULL) || (ctxt->error == NULL))
2192 return;
2193
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002194#ifdef DEBUG_ERROR
2195 xmlGenericError(xmlGenericErrorContext,
2196 "Adding error %d\n", err);
2197#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002198 /*
2199 * generate the error directly
2200 */
2201 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2202 xmlNodePtr node, seq;
2203 /*
2204 * Flush first any stacked error which might be the
2205 * real cause of the problem.
2206 */
2207 if (ctxt->errNr != 0)
2208 xmlRelaxNGDumpValidError(ctxt);
2209 if (ctxt->state != NULL) {
2210 node = ctxt->state->node;
2211 seq = ctxt->state->seq;
2212 } else {
2213 node = seq = NULL;
2214 }
2215 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2216 }
2217 /*
2218 * Stack the error for later processing if needed
2219 */
2220 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002221 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002222 }
2223}
2224
Daniel Veillard6eadf632003-01-23 18:29:16 +00002225
2226/************************************************************************
2227 * *
2228 * Type library hooks *
2229 * *
2230 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002231static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2232 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002233
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002234/**
2235 * xmlRelaxNGSchemaTypeHave:
2236 * @data: data needed for the library
2237 * @type: the type name
2238 *
2239 * Check if the given type is provided by
2240 * the W3C XMLSchema Datatype library.
2241 *
2242 * Returns 1 if yes, 0 if no and -1 in case of error.
2243 */
2244static int
2245xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002246 const xmlChar *type) {
2247 xmlSchemaTypePtr typ;
2248
2249 if (type == NULL)
2250 return(-1);
2251 typ = xmlSchemaGetPredefinedType(type,
2252 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2253 if (typ == NULL)
2254 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002255 return(1);
2256}
2257
2258/**
2259 * xmlRelaxNGSchemaTypeCheck:
2260 * @data: data needed for the library
2261 * @type: the type name
2262 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002263 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002264 *
2265 * Check if the given type and value are validated by
2266 * the W3C XMLSchema Datatype library.
2267 *
2268 * Returns 1 if yes, 0 if no and -1 in case of error.
2269 */
2270static int
2271xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002272 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002273 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002274 void **result,
2275 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002276 xmlSchemaTypePtr typ;
2277 int ret;
2278
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002279 if ((type == NULL) || (value == NULL))
2280 return(-1);
2281 typ = xmlSchemaGetPredefinedType(type,
2282 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2283 if (typ == NULL)
2284 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002285 ret = xmlSchemaValPredefTypeNode(typ, value,
2286 (xmlSchemaValPtr *) result, node);
2287 if (ret == 2) /* special ID error code */
2288 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002289 if (ret == 0)
2290 return(1);
2291 if (ret > 0)
2292 return(0);
2293 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002294}
2295
2296/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002297 * xmlRelaxNGSchemaFacetCheck:
2298 * @data: data needed for the library
2299 * @type: the type name
2300 * @facet: the facet name
2301 * @val: the facet value
2302 * @strval: the string value
2303 * @value: the value to check
2304 *
2305 * Function provided by a type library to check a value facet
2306 *
2307 * Returns 1 if yes, 0 if no and -1 in case of error.
2308 */
2309static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002310xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002311 const xmlChar *facetname, const xmlChar *val,
2312 const xmlChar *strval, void *value) {
2313 xmlSchemaFacetPtr facet;
2314 xmlSchemaTypePtr typ;
2315 int ret;
2316
2317 if ((type == NULL) || (strval == NULL))
2318 return(-1);
2319 typ = xmlSchemaGetPredefinedType(type,
2320 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2321 if (typ == NULL)
2322 return(-1);
2323
2324 facet = xmlSchemaNewFacet();
2325 if (facet == NULL)
2326 return(-1);
2327
2328 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2329 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2330 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2331 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2332 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2333 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2334 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2335 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2336 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2337 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2338 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2339 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2340 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2341 facet->type = XML_SCHEMA_FACET_PATTERN;
2342 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2343 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2344 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2345 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2346 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2347 facet->type = XML_SCHEMA_FACET_LENGTH;
2348 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2349 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2350 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2351 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2352 } else {
2353 xmlSchemaFreeFacet(facet);
2354 return(-1);
2355 }
2356 facet->value = xmlStrdup(val);
2357 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2358 if (ret != 0) {
2359 xmlSchemaFreeFacet(facet);
2360 return(-1);
2361 }
2362 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2363 xmlSchemaFreeFacet(facet);
2364 if (ret != 0)
2365 return(-1);
2366 return(0);
2367}
2368
2369/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002370 * xmlRelaxNGSchemaFreeValue:
2371 * @data: data needed for the library
2372 * @value: the value to free
2373 *
2374 * Function provided by a type library to free a Schemas value
2375 *
2376 * Returns 1 if yes, 0 if no and -1 in case of error.
2377 */
2378static void
2379xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2380 xmlSchemaFreeValue(value);
2381}
2382
2383/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002384 * xmlRelaxNGSchemaTypeCompare:
2385 * @data: data needed for the library
2386 * @type: the type name
2387 * @value1: the first value
2388 * @value2: the second value
2389 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002390 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002391 * Datatype library.
2392 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002393 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002394 */
2395static int
2396xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002397 const xmlChar *type,
2398 const xmlChar *value1,
2399 xmlNodePtr ctxt1,
2400 void *comp1,
2401 const xmlChar *value2,
2402 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002403 int ret;
2404 xmlSchemaTypePtr typ;
2405 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2406
2407 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2408 return(-1);
2409 typ = xmlSchemaGetPredefinedType(type,
2410 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2411 if (typ == NULL)
2412 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002413 if (comp1 == NULL) {
2414 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2415 if (ret != 0)
2416 return(-1);
2417 if (res1 == NULL)
2418 return(-1);
2419 } else {
2420 res1 = (xmlSchemaValPtr) comp1;
2421 }
2422 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002423 if (ret != 0) {
2424 xmlSchemaFreeValue(res1);
2425 return(-1);
2426 }
2427 if (res1 == NULL) {
2428 xmlSchemaFreeValue(res1);
2429 return(-1);
2430 }
2431 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002432 if (res1 != (xmlSchemaValPtr) comp1)
2433 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002434 xmlSchemaFreeValue(res2);
2435 if (ret == -2)
2436 return(-1);
2437 if (ret == 0)
2438 return(1);
2439 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002440}
2441
2442/**
2443 * xmlRelaxNGDefaultTypeHave:
2444 * @data: data needed for the library
2445 * @type: the type name
2446 *
2447 * Check if the given type is provided by
2448 * the default datatype library.
2449 *
2450 * Returns 1 if yes, 0 if no and -1 in case of error.
2451 */
2452static int
2453xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2454 if (type == NULL)
2455 return(-1);
2456 if (xmlStrEqual(type, BAD_CAST "string"))
2457 return(1);
2458 if (xmlStrEqual(type, BAD_CAST "token"))
2459 return(1);
2460 return(0);
2461}
2462
2463/**
2464 * xmlRelaxNGDefaultTypeCheck:
2465 * @data: data needed for the library
2466 * @type: the type name
2467 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002468 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002469 *
2470 * Check if the given type and value are validated by
2471 * the default datatype library.
2472 *
2473 * Returns 1 if yes, 0 if no and -1 in case of error.
2474 */
2475static int
2476xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2477 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002478 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002479 void **result ATTRIBUTE_UNUSED,
2480 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002481 if (value == NULL)
2482 return(-1);
2483 if (xmlStrEqual(type, BAD_CAST "string"))
2484 return(1);
2485 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002486 return(1);
2487 }
2488
2489 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002490}
2491
2492/**
2493 * xmlRelaxNGDefaultTypeCompare:
2494 * @data: data needed for the library
2495 * @type: the type name
2496 * @value1: the first value
2497 * @value2: the second value
2498 *
2499 * Compare two values accordingly a type from the default
2500 * datatype library.
2501 *
2502 * Returns 1 if yes, 0 if no and -1 in case of error.
2503 */
2504static int
2505xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002506 const xmlChar *type,
2507 const xmlChar *value1,
2508 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2509 void *comp1 ATTRIBUTE_UNUSED,
2510 const xmlChar *value2,
2511 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002512 int ret = -1;
2513
2514 if (xmlStrEqual(type, BAD_CAST "string")) {
2515 ret = xmlStrEqual(value1, value2);
2516 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2517 if (!xmlStrEqual(value1, value2)) {
2518 xmlChar *nval, *nvalue;
2519
2520 /*
2521 * TODO: trivial optimizations are possible by
2522 * computing at compile-time
2523 */
2524 nval = xmlRelaxNGNormalize(NULL, value1);
2525 nvalue = xmlRelaxNGNormalize(NULL, value2);
2526
Daniel Veillardd4310742003-02-18 21:12:46 +00002527 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002528 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002529 else if (xmlStrEqual(nval, nvalue))
2530 ret = 1;
2531 else
2532 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002533 if (nval != NULL)
2534 xmlFree(nval);
2535 if (nvalue != NULL)
2536 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002537 } else
2538 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002539 }
2540 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002541}
2542
2543static int xmlRelaxNGTypeInitialized = 0;
2544static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2545
2546/**
2547 * xmlRelaxNGFreeTypeLibrary:
2548 * @lib: the type library structure
2549 * @namespace: the URI bound to the library
2550 *
2551 * Free the structure associated to the type library
2552 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002553static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002554xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2555 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2556 if (lib == NULL)
2557 return;
2558 if (lib->namespace != NULL)
2559 xmlFree((xmlChar *)lib->namespace);
2560 xmlFree(lib);
2561}
2562
2563/**
2564 * xmlRelaxNGRegisterTypeLibrary:
2565 * @namespace: the URI bound to the library
2566 * @data: data associated to the library
2567 * @have: the provide function
2568 * @check: the checking function
2569 * @comp: the comparison function
2570 *
2571 * Register a new type library
2572 *
2573 * Returns 0 in case of success and -1 in case of error.
2574 */
2575static int
2576xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2577 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002578 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2579 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002580 xmlRelaxNGTypeLibraryPtr lib;
2581 int ret;
2582
2583 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2584 (check == NULL) || (comp == NULL))
2585 return(-1);
2586 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2587 xmlGenericError(xmlGenericErrorContext,
2588 "Relax-NG types library '%s' already registered\n",
2589 namespace);
2590 return(-1);
2591 }
2592 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2593 if (lib == NULL) {
2594 xmlGenericError(xmlGenericErrorContext,
2595 "Relax-NG types library '%s' malloc() failed\n",
2596 namespace);
2597 return (-1);
2598 }
2599 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2600 lib->namespace = xmlStrdup(namespace);
2601 lib->data = data;
2602 lib->have = have;
2603 lib->comp = comp;
2604 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002605 lib->facet = facet;
2606 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002607 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2608 if (ret < 0) {
2609 xmlGenericError(xmlGenericErrorContext,
2610 "Relax-NG types library failed to register '%s'\n",
2611 namespace);
2612 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2613 return(-1);
2614 }
2615 return(0);
2616}
2617
2618/**
2619 * xmlRelaxNGInitTypes:
2620 *
2621 * Initilize the default type libraries.
2622 *
2623 * Returns 0 in case of success and -1 in case of error.
2624 */
2625static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002626xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002627 if (xmlRelaxNGTypeInitialized != 0)
2628 return(0);
2629 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2630 if (xmlRelaxNGRegisteredTypes == NULL) {
2631 xmlGenericError(xmlGenericErrorContext,
2632 "Failed to allocate sh table for Relax-NG types\n");
2633 return(-1);
2634 }
2635 xmlRelaxNGRegisterTypeLibrary(
2636 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2637 NULL,
2638 xmlRelaxNGSchemaTypeHave,
2639 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002640 xmlRelaxNGSchemaTypeCompare,
2641 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002642 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002643 xmlRelaxNGRegisterTypeLibrary(
2644 xmlRelaxNGNs,
2645 NULL,
2646 xmlRelaxNGDefaultTypeHave,
2647 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002648 xmlRelaxNGDefaultTypeCompare,
2649 NULL,
2650 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002651 xmlRelaxNGTypeInitialized = 1;
2652 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002653}
2654
2655/**
2656 * xmlRelaxNGCleanupTypes:
2657 *
2658 * Cleanup the default Schemas type library associated to RelaxNG
2659 */
2660void
2661xmlRelaxNGCleanupTypes(void) {
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002662 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002663 if (xmlRelaxNGTypeInitialized == 0)
2664 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002665 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2666 xmlRelaxNGFreeTypeLibrary);
2667 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002668}
2669
2670/************************************************************************
2671 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002672 * Compiling element content into regexp *
2673 * *
2674 * Sometime the element content can be compiled into a pure regexp, *
2675 * This allows a faster execution and streamability at that level *
2676 * *
2677 ************************************************************************/
2678
Daniel Veillard52b48c72003-04-13 19:53:42 +00002679static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2680 xmlRelaxNGDefinePtr def);
2681
Daniel Veillard952379b2003-03-17 15:37:12 +00002682/**
2683 * xmlRelaxNGIsCompileable:
2684 * @define: the definition to check
2685 *
2686 * Check if a definition is nullable.
2687 *
2688 * Returns 1 if yes, 0 if no and -1 in case of error
2689 */
2690static int
2691xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00002692 int ret = -1;
2693
Daniel Veillard952379b2003-03-17 15:37:12 +00002694 if (def == NULL) {
2695 return(-1);
2696 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002697 if ((def->type != XML_RELAXNG_ELEMENT) &&
2698 (def->dflags & IS_COMPILABLE))
2699 return(1);
2700 if ((def->type != XML_RELAXNG_ELEMENT) &&
2701 (def->dflags & IS_NOT_COMPILABLE))
2702 return(0);
Daniel Veillard952379b2003-03-17 15:37:12 +00002703 switch(def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002704 case XML_RELAXNG_NOOP:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002705 ret = xmlRelaxNGIsCompileable(def->content);
2706 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002707 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002708 case XML_RELAXNG_EMPTY:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002709 ret = 1;
2710 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002711 case XML_RELAXNG_ELEMENT:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002712 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2713 ((def->dflags & IS_COMPILABLE) == 0)) {
Daniel Veillard2134ab12003-07-23 19:56:29 +00002714 xmlRelaxNGDefinePtr list;
2715 list = def->content;
2716 while (list != NULL) {
2717 ret = xmlRelaxNGIsCompileable(list);
2718 if (ret != 1)
2719 break;
2720 list = list->next;
2721 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002722 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2723 if (ret == 1) def->dflags |= IS_COMPILABLE;
2724 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00002725 if (ret == 1) {
2726 if ((def->nameClass != NULL) || (def->name == NULL))
2727 ret = 0;
2728 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002729 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002730 case XML_RELAXNG_REF:
2731 case XML_RELAXNG_EXTERNALREF:
2732 case XML_RELAXNG_PARENTREF:
2733 if (def->depth == -20) {
2734 return(1);
2735 } else {
2736 xmlRelaxNGDefinePtr list;
2737
2738 def->depth = -20;
2739 list = def->content;
2740 while (list != NULL) {
2741 ret = xmlRelaxNGIsCompileable(list);
2742 if (ret != 1)
2743 break;
2744 list = list->next;
2745 }
2746 }
2747 break;
2748 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002749 case XML_RELAXNG_OPTIONAL:
2750 case XML_RELAXNG_ZEROORMORE:
2751 case XML_RELAXNG_ONEORMORE:
2752 case XML_RELAXNG_CHOICE:
2753 case XML_RELAXNG_GROUP:
2754 case XML_RELAXNG_DEF: {
2755 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002756
2757 list = def->content;
2758 while (list != NULL) {
2759 ret = xmlRelaxNGIsCompileable(list);
2760 if (ret != 1)
Daniel Veillard52b48c72003-04-13 19:53:42 +00002761 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002762 list = list->next;
2763 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002764 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002765 }
2766 case XML_RELAXNG_EXCEPT:
2767 case XML_RELAXNG_ATTRIBUTE:
2768 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002769 case XML_RELAXNG_DATATYPE:
2770 case XML_RELAXNG_LIST:
2771 case XML_RELAXNG_PARAM:
2772 case XML_RELAXNG_VALUE:
2773 ret = 0;
2774 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002775 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002776 ret = -1;
2777 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002778 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002779 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2780 if (ret == 1) def->dflags |= IS_COMPILABLE;
2781 return(ret);
2782}
2783
2784/**
2785 * xmlRelaxNGCompile:
2786 * ctxt: the RelaxNG parser context
2787 * @define: the definition tree to compile
2788 *
2789 * Compile the set of definitions, it works recursively, till the
2790 * element boundaries, where it tries to compile the content if possible
2791 *
2792 * Returns 0 if success and -1 in case of error
2793 */
2794static int
2795xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2796 int ret = 0;
2797 xmlRelaxNGDefinePtr list;
2798
2799 if ((ctxt == NULL) || (def == NULL)) return(-1);
2800
2801 switch(def->type) {
2802 case XML_RELAXNG_START:
2803 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
2804 xmlAutomataPtr oldam = ctxt->am;
2805 xmlAutomataStatePtr oldstate = ctxt->state;
2806
2807 def->depth = -25;
2808
2809 list = def->content;
2810 ctxt->am = xmlNewAutomata();
2811 if (ctxt->am == NULL)
2812 return(-1);
2813 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2814 while (list != NULL) {
2815 xmlRelaxNGCompile(ctxt, list);
2816 list = list->next;
2817 }
2818 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2819 def->contModel = xmlAutomataCompile(ctxt->am);
2820 xmlRegexpIsDeterminist(def->contModel);
2821
2822 xmlFreeAutomata(ctxt->am);
2823 ctxt->state = oldstate;
2824 ctxt->am = oldam;
2825 }
2826 break;
2827 case XML_RELAXNG_ELEMENT:
2828 if ((ctxt->am != NULL) && (def->name != NULL)) {
2829 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002830 ctxt->state, NULL, def->name, def->ns, def);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002831 }
2832 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2833 xmlAutomataPtr oldam = ctxt->am;
2834 xmlAutomataStatePtr oldstate = ctxt->state;
2835
2836 def->depth = -25;
2837
2838 list = def->content;
2839 ctxt->am = xmlNewAutomata();
2840 if (ctxt->am == NULL)
2841 return(-1);
2842 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2843 while (list != NULL) {
2844 xmlRelaxNGCompile(ctxt, list);
2845 list = list->next;
2846 }
2847 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2848 def->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002849 if (!xmlRegexpIsDeterminist(def->contModel)) {
2850 /*
2851 * we can only use the automata if it is determinist
2852 */
2853 xmlRegFreeRegexp(def->contModel);
2854 def->contModel = NULL;
2855 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002856 xmlFreeAutomata(ctxt->am);
2857 ctxt->state = oldstate;
2858 ctxt->am = oldam;
2859 } else {
2860 xmlAutomataPtr oldam = ctxt->am;
2861
2862 /*
2863 * we can't build the content model for this element content
2864 * but it still might be possible to build it for some of its
2865 * children, recurse.
2866 */
2867 ret = xmlRelaxNGTryCompile(ctxt, def);
2868 ctxt->am = oldam;
2869 }
2870 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002871 case XML_RELAXNG_NOOP:
2872 ret = xmlRelaxNGCompile(ctxt, def->content);
2873 break;
2874 case XML_RELAXNG_OPTIONAL: {
2875 xmlAutomataStatePtr oldstate = ctxt->state;
2876
2877 xmlRelaxNGCompile(ctxt, def->content);
2878 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2879 break;
2880 }
2881 case XML_RELAXNG_ZEROORMORE: {
2882 xmlAutomataStatePtr oldstate;
2883
2884 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2885 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002886 list = def->content;
2887 while (list != NULL) {
2888 xmlRelaxNGCompile(ctxt, list);
2889 list = list->next;
2890 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002891 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2892 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2893 break;
2894 }
2895 case XML_RELAXNG_ONEORMORE: {
2896 xmlAutomataStatePtr oldstate;
2897
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002898 list = def->content;
2899 while (list != NULL) {
2900 xmlRelaxNGCompile(ctxt, list);
2901 list = list->next;
2902 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002903 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002904 list = def->content;
2905 while (list != NULL) {
2906 xmlRelaxNGCompile(ctxt, list);
2907 list = list->next;
2908 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002909 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2910 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2911 break;
2912 }
2913 case XML_RELAXNG_CHOICE: {
2914 xmlAutomataStatePtr target = NULL;
2915 xmlAutomataStatePtr oldstate = ctxt->state;
2916
2917 list = def->content;
2918 while (list != NULL) {
2919 ctxt->state = oldstate;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002920 ret = xmlRelaxNGCompile(ctxt, list);
2921 if (ret != 0)
2922 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002923 if (target == NULL)
2924 target = ctxt->state;
2925 else {
2926 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, target);
2927 }
2928 list = list->next;
2929 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002930 ctxt->state = target;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002931
2932 break;
2933 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00002934 case XML_RELAXNG_REF:
2935 case XML_RELAXNG_EXTERNALREF:
2936 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002937 case XML_RELAXNG_GROUP:
2938 case XML_RELAXNG_DEF:
2939 list = def->content;
2940 while (list != NULL) {
Daniel Veillard2134ab12003-07-23 19:56:29 +00002941 ret = xmlRelaxNGCompile(ctxt, list);
2942 if (ret != 0)
2943 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002944 list = list->next;
2945 }
2946 break;
2947 case XML_RELAXNG_TEXT: {
2948 xmlAutomataStatePtr oldstate;
2949
2950 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2951 oldstate = ctxt->state;
2952 xmlRelaxNGCompile(ctxt, def->content);
2953 xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state,
2954 BAD_CAST "#text", NULL);
2955 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2956 break;
2957 }
2958 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002959 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002960 break;
2961 case XML_RELAXNG_EXCEPT:
2962 case XML_RELAXNG_ATTRIBUTE:
2963 case XML_RELAXNG_INTERLEAVE:
2964 case XML_RELAXNG_NOT_ALLOWED:
2965 case XML_RELAXNG_DATATYPE:
2966 case XML_RELAXNG_LIST:
2967 case XML_RELAXNG_PARAM:
2968 case XML_RELAXNG_VALUE:
Daniel Veillardac297932003-04-17 12:55:35 +00002969 /* This should not happen and generate an internal error */
2970 fprintf(stderr, "RNG internal error trying to compile %s\n",
2971 xmlRelaxNGDefName(def));
Daniel Veillard52b48c72003-04-13 19:53:42 +00002972 break;
2973 }
2974 return(ret);
2975}
2976
2977/**
2978 * xmlRelaxNGTryCompile:
2979 * ctxt: the RelaxNG parser context
2980 * @define: the definition tree to compile
2981 *
2982 * Try to compile the set of definitions, it works recursively,
2983 * possibly ignoring parts which cannot be compiled.
2984 *
2985 * Returns 0 if success and -1 in case of error
2986 */
2987static int
2988xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2989 int ret = 0;
2990 xmlRelaxNGDefinePtr list;
2991
2992 if ((ctxt == NULL) || (def == NULL)) return(-1);
2993
2994 if ((def->type == XML_RELAXNG_START) ||
2995 (def->type == XML_RELAXNG_ELEMENT)) {
2996 ret = xmlRelaxNGIsCompileable(def);
2997 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2998 ctxt->am = NULL;
2999 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003000#ifdef DEBUG_PROGRESSIVE
3001 if (ret == 0) {
3002 if (def->type == XML_RELAXNG_START)
3003 xmlGenericError(xmlGenericErrorContext,
3004 "compiled the start\n");
3005 else
3006 xmlGenericError(xmlGenericErrorContext,
3007 "compiled element %s\n", def->name);
3008 } else {
3009 if (def->type == XML_RELAXNG_START)
3010 xmlGenericError(xmlGenericErrorContext,
3011 "failed to compile the start\n");
3012 else
3013 xmlGenericError(xmlGenericErrorContext,
3014 "failed to compile element %s\n", def->name);
3015 }
3016#endif
Daniel Veillard52b48c72003-04-13 19:53:42 +00003017 return(ret);
3018 }
3019 }
3020 switch(def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003021 case XML_RELAXNG_NOOP:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003022 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3023 break;
3024 case XML_RELAXNG_TEXT:
3025 case XML_RELAXNG_DATATYPE:
3026 case XML_RELAXNG_LIST:
3027 case XML_RELAXNG_PARAM:
3028 case XML_RELAXNG_VALUE:
3029 case XML_RELAXNG_EMPTY:
3030 case XML_RELAXNG_ELEMENT:
3031 ret = 0;
3032 break;
3033 case XML_RELAXNG_OPTIONAL:
3034 case XML_RELAXNG_ZEROORMORE:
3035 case XML_RELAXNG_ONEORMORE:
3036 case XML_RELAXNG_CHOICE:
3037 case XML_RELAXNG_GROUP:
3038 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003039 case XML_RELAXNG_START:
3040 case XML_RELAXNG_REF:
3041 case XML_RELAXNG_EXTERNALREF:
3042 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003043 list = def->content;
3044 while (list != NULL) {
3045 ret = xmlRelaxNGTryCompile(ctxt, list);
3046 if (ret != 0)
3047 break;
3048 list = list->next;
3049 }
3050 break;
3051 case XML_RELAXNG_EXCEPT:
3052 case XML_RELAXNG_ATTRIBUTE:
3053 case XML_RELAXNG_INTERLEAVE:
3054 case XML_RELAXNG_NOT_ALLOWED:
3055 ret = 0;
3056 break;
3057 }
3058 return(ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003059}
3060
3061/************************************************************************
3062 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003063 * Parsing functions *
3064 * *
3065 ************************************************************************/
3066
3067static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
3068 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3069static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
3070 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3071static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00003072 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003073static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
3074 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003075static xmlRelaxNGPtr xmlRelaxNGParseDocument(
3076 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003077static int xmlRelaxNGParseGrammarContent(
3078 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003079static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
3080 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3081 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00003082static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
3083 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003084static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3085 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003086
3087
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003088#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003089
3090/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003091 * xmlRelaxNGIsNullable:
3092 * @define: the definition to verify
3093 *
3094 * Check if a definition is nullable.
3095 *
3096 * Returns 1 if yes, 0 if no and -1 in case of error
3097 */
3098static int
3099xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
3100 int ret;
3101 if (define == NULL)
3102 return(-1);
3103
Daniel Veillarde063f482003-03-21 16:53:17 +00003104 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003105 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003106 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003107 return(0);
3108 switch (define->type) {
3109 case XML_RELAXNG_EMPTY:
3110 case XML_RELAXNG_TEXT:
3111 ret = 1; break;
3112 case XML_RELAXNG_NOOP:
3113 case XML_RELAXNG_DEF:
3114 case XML_RELAXNG_REF:
3115 case XML_RELAXNG_EXTERNALREF:
3116 case XML_RELAXNG_PARENTREF:
3117 case XML_RELAXNG_ONEORMORE:
3118 ret = xmlRelaxNGIsNullable(define->content);
3119 break;
3120 case XML_RELAXNG_EXCEPT:
3121 case XML_RELAXNG_NOT_ALLOWED:
3122 case XML_RELAXNG_ELEMENT:
3123 case XML_RELAXNG_DATATYPE:
3124 case XML_RELAXNG_PARAM:
3125 case XML_RELAXNG_VALUE:
3126 case XML_RELAXNG_LIST:
3127 case XML_RELAXNG_ATTRIBUTE:
3128 ret = 0; break;
3129 case XML_RELAXNG_CHOICE: {
3130 xmlRelaxNGDefinePtr list = define->content;
3131
3132 while (list != NULL) {
3133 ret = xmlRelaxNGIsNullable(list);
3134 if (ret != 0)
3135 goto done;
3136 list = list->next;
3137 }
3138 ret = 0; break;
3139 }
3140 case XML_RELAXNG_START:
3141 case XML_RELAXNG_INTERLEAVE:
3142 case XML_RELAXNG_GROUP: {
3143 xmlRelaxNGDefinePtr list = define->content;
3144
3145 while (list != NULL) {
3146 ret = xmlRelaxNGIsNullable(list);
3147 if (ret != 1)
3148 goto done;
3149 list = list->next;
3150 }
3151 return(1);
3152 }
3153 default:
3154 return(-1);
3155 }
3156done:
3157 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003158 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003159 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00003160 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003161 return(ret);
3162}
3163
3164/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003165 * xmlRelaxNGIsBlank:
3166 * @str: a string
3167 *
3168 * Check if a string is ignorable c.f. 4.2. Whitespace
3169 *
3170 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3171 */
3172static int
3173xmlRelaxNGIsBlank(xmlChar *str) {
3174 if (str == NULL)
3175 return(1);
3176 while (*str != 0) {
3177 if (!(IS_BLANK(*str))) return(0);
3178 str++;
3179 }
3180 return(1);
3181}
3182
Daniel Veillard6eadf632003-01-23 18:29:16 +00003183/**
3184 * xmlRelaxNGGetDataTypeLibrary:
3185 * @ctxt: a Relax-NG parser context
3186 * @node: the current data or value element
3187 *
3188 * Applies algorithm from 4.3. datatypeLibrary attribute
3189 *
3190 * Returns the datatypeLibary value or NULL if not found
3191 */
3192static xmlChar *
3193xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3194 xmlNodePtr node) {
3195 xmlChar *ret, *escape;
3196
Daniel Veillard6eadf632003-01-23 18:29:16 +00003197 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3198 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3199 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003200 if (ret[0] == 0) {
3201 xmlFree(ret);
3202 return(NULL);
3203 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003204 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00003205 if (escape == NULL) {
3206 return(ret);
3207 }
3208 xmlFree(ret);
3209 return(escape);
3210 }
3211 }
3212 node = node->parent;
3213 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003214 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3215 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003216 if (ret[0] == 0) {
3217 xmlFree(ret);
3218 return(NULL);
3219 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003220 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3221 if (escape == NULL) {
3222 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003223 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003224 xmlFree(ret);
3225 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003226 }
3227 node = node->parent;
3228 }
3229 return(NULL);
3230}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003231
3232/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003233 * xmlRelaxNGParseValue:
3234 * @ctxt: a Relax-NG parser context
3235 * @node: the data node.
3236 *
3237 * parse the content of a RelaxNG value node.
3238 *
3239 * Returns the definition pointer or NULL in case of error
3240 */
3241static xmlRelaxNGDefinePtr
3242xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3243 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003244 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003245 xmlChar *type;
3246 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003247 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003248
Daniel Veillardfd573f12003-03-16 17:52:32 +00003249 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003250 if (def == NULL)
3251 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003252 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003253
3254 type = xmlGetProp(node, BAD_CAST "type");
3255 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003256 xmlRelaxNGNormExtSpace(type);
3257 if (xmlValidateNCName(type, 0)) {
3258 if (ctxt->error != NULL)
3259 ctxt->error(ctxt->userData,
3260 "value type '%s' is not an NCName\n",
3261 type);
3262 ctxt->nbErrors++;
3263 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003264 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3265 if (library == NULL)
3266 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3267
3268 def->name = type;
3269 def->ns = library;
3270
3271 lib = (xmlRelaxNGTypeLibraryPtr)
3272 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3273 if (lib == NULL) {
3274 if (ctxt->error != NULL)
3275 ctxt->error(ctxt->userData,
3276 "Use of unregistered type library '%s'\n",
3277 library);
3278 ctxt->nbErrors++;
3279 def->data = NULL;
3280 } else {
3281 def->data = lib;
3282 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003283 if (ctxt->error != NULL)
3284 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003285 "Internal error with type library '%s': no 'have'\n",
3286 library);
3287 ctxt->nbErrors++;
3288 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003289 success = lib->have(lib->data, def->name);
3290 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003291 if (ctxt->error != NULL)
3292 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003293 "Error type '%s' is not exported by type library '%s'\n",
3294 def->name, library);
3295 ctxt->nbErrors++;
3296 }
3297 }
3298 }
3299 }
3300 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00003301 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003302 } else if (((node->children->type != XML_TEXT_NODE) &&
3303 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00003304 (node->children->next != NULL)) {
3305 if (ctxt->error != NULL)
3306 ctxt->error(ctxt->userData,
3307 "Expecting a single text value for <value>content\n");
3308 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003309 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00003310 def->value = xmlNodeGetContent(node);
3311 if (def->value == NULL) {
3312 if (ctxt->error != NULL)
3313 ctxt->error(ctxt->userData,
3314 "Element <value> has no content\n");
3315 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003316 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3317 void *val = NULL;
3318
3319 success = lib->check(lib->data, def->name, def->value, &val, node);
3320 if (success != 1) {
3321 if (ctxt->error != NULL)
3322 ctxt->error(ctxt->userData,
3323 "Value '%s' is not acceptable for type '%s'\n",
3324 def->value, def->name);
3325 ctxt->nbErrors++;
3326 } else {
3327 if (val != NULL)
3328 def->attrs = val;
3329 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003330 }
3331 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003332 return(def);
3333}
3334
3335/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003336 * xmlRelaxNGParseData:
3337 * @ctxt: a Relax-NG parser context
3338 * @node: the data node.
3339 *
3340 * parse the content of a RelaxNG data node.
3341 *
3342 * Returns the definition pointer or NULL in case of error
3343 */
3344static xmlRelaxNGDefinePtr
3345xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003346 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003347 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003348 xmlRelaxNGTypeLibraryPtr lib;
3349 xmlChar *type;
3350 xmlChar *library;
3351 xmlNodePtr content;
3352 int tmp;
3353
3354 type = xmlGetProp(node, BAD_CAST "type");
3355 if (type == NULL) {
3356 if (ctxt->error != NULL)
3357 ctxt->error(ctxt->userData,
3358 "data has no type\n");
3359 ctxt->nbErrors++;
3360 return(NULL);
3361 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003362 xmlRelaxNGNormExtSpace(type);
3363 if (xmlValidateNCName(type, 0)) {
3364 if (ctxt->error != NULL)
3365 ctxt->error(ctxt->userData,
3366 "data type '%s' is not an NCName\n",
3367 type);
3368 ctxt->nbErrors++;
3369 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003370 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3371 if (library == NULL)
3372 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3373
Daniel Veillardfd573f12003-03-16 17:52:32 +00003374 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003375 if (def == NULL) {
3376 xmlFree(type);
3377 return(NULL);
3378 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003379 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003380 def->name = type;
3381 def->ns = library;
3382
3383 lib = (xmlRelaxNGTypeLibraryPtr)
3384 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3385 if (lib == NULL) {
3386 if (ctxt->error != NULL)
3387 ctxt->error(ctxt->userData,
3388 "Use of unregistered type library '%s'\n",
3389 library);
3390 ctxt->nbErrors++;
3391 def->data = NULL;
3392 } else {
3393 def->data = lib;
3394 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003395 if (ctxt->error != NULL)
3396 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003397 "Internal error with type library '%s': no 'have'\n",
3398 library);
3399 ctxt->nbErrors++;
3400 } else {
3401 tmp = lib->have(lib->data, def->name);
3402 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003403 if (ctxt->error != NULL)
3404 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003405 "Error type '%s' is not exported by type library '%s'\n",
3406 def->name, library);
3407 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003408 } else if ((xmlStrEqual(library, BAD_CAST
3409 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3410 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3411 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3412 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003413 }
3414 }
3415 }
3416 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003417
3418 /*
3419 * Handle optional params
3420 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003421 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003422 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3423 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003424 if (xmlStrEqual(library,
3425 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3426 if (ctxt->error != NULL)
3427 ctxt->error(ctxt->userData,
3428 "Type library '%s' does not allow type parameters\n",
3429 library);
3430 ctxt->nbErrors++;
3431 content = content->next;
3432 while ((content != NULL) &&
3433 (xmlStrEqual(content->name, BAD_CAST "param")))
3434 content = content->next;
3435 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003436 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003437 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003438 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003439 param->name = xmlGetProp(content, BAD_CAST "name");
3440 if (param->name == NULL) {
3441 if (ctxt->error != NULL)
3442 ctxt->error(ctxt->userData,
3443 "param has no name\n");
3444 ctxt->nbErrors++;
3445 }
3446 param->value = xmlNodeGetContent(content);
3447 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003448 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003449 } else {
3450 lastparam->next = param;
3451 lastparam = param;
3452 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003453 if (lib != NULL) {
3454 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003455 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003456 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003457 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003458 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003459 /*
3460 * Handle optional except
3461 */
3462 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3463 xmlNodePtr child;
3464 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3465
Daniel Veillardfd573f12003-03-16 17:52:32 +00003466 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003467 if (except == NULL) {
3468 return(def);
3469 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003470 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003471 child = content->children;
3472 if (last == NULL) {
3473 def->content = except;
3474 } else {
3475 last->next = except;
3476 }
3477 if (child == NULL) {
3478 if (ctxt->error != NULL)
3479 ctxt->error(ctxt->userData,
3480 "except has no content\n");
3481 ctxt->nbErrors++;
3482 }
3483 while (child != NULL) {
3484 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3485 if (tmp2 != NULL) {
3486 if (last2 == NULL) {
3487 except->content = last2 = tmp2;
3488 } else {
3489 last2->next = tmp2;
3490 last2 = tmp2;
3491 }
3492 }
3493 child = child->next;
3494 }
3495 content = content->next;
3496 }
3497 /*
3498 * Check there is no unhandled data
3499 */
3500 if (content != NULL) {
3501 if (ctxt->error != NULL)
3502 ctxt->error(ctxt->userData,
3503 "Element data has unexpected content %s\n", content->name);
3504 ctxt->nbErrors++;
3505 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003506
3507 return(def);
3508}
3509
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003510static const xmlChar *invalidName = BAD_CAST "\1";
3511
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003512/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003513 * xmlRelaxNGCompareNameClasses:
3514 * @defs1: the first element/attribute defs
3515 * @defs2: the second element/attribute defs
3516 * @name: the restriction on the name
3517 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003518 *
3519 * Compare the 2 lists of element definitions. The comparison is
3520 * that if both lists do not accept the same QNames, it returns 1
3521 * If the 2 lists can accept the same QName the comparison returns 0
3522 *
3523 * Returns 1 disttinct, 0 if equal
3524 */
3525static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003526xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3527 xmlRelaxNGDefinePtr def2) {
3528 int ret = 1;
3529 xmlNode node;
3530 xmlNs ns;
3531 xmlRelaxNGValidCtxt ctxt;
3532 ctxt.flags = FLAGS_IGNORABLE;
3533
Daniel Veillard42f12e92003-03-07 18:32:59 +00003534 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3535
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003536 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3537 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3538 if (def2->type == XML_RELAXNG_TEXT)
3539 return(1);
3540 if (def1->name != NULL) {
3541 node.name = def1->name;
3542 } else {
3543 node.name = invalidName;
3544 }
3545 node.ns = &ns;
3546 if (def1->ns != NULL) {
3547 if (def1->ns[0] == 0) {
3548 node.ns = NULL;
3549 } else {
3550 ns.href = def1->ns;
3551 }
3552 } else {
3553 ns.href = invalidName;
3554 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003555 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003556 if (def1->nameClass != NULL) {
3557 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3558 } else {
3559 ret = 0;
3560 }
3561 } else {
3562 ret = 1;
3563 }
3564 } else if (def1->type == XML_RELAXNG_TEXT) {
3565 if (def2->type == XML_RELAXNG_TEXT)
3566 return(0);
3567 return(1);
3568 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003569 TODO
3570 ret = 0;
3571 } else {
3572 TODO
3573 ret = 0;
3574 }
3575 if (ret == 0)
3576 return(ret);
3577 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3578 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3579 if (def2->name != NULL) {
3580 node.name = def2->name;
3581 } else {
3582 node.name = invalidName;
3583 }
3584 node.ns = &ns;
3585 if (def2->ns != NULL) {
3586 if (def2->ns[0] == 0) {
3587 node.ns = NULL;
3588 } else {
3589 ns.href = def2->ns;
3590 }
3591 } else {
3592 ns.href = invalidName;
3593 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003594 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003595 if (def2->nameClass != NULL) {
3596 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3597 } else {
3598 ret = 0;
3599 }
3600 } else {
3601 ret = 1;
3602 }
3603 } else {
3604 TODO
3605 ret = 0;
3606 }
3607
3608 return(ret);
3609}
3610
3611/**
3612 * xmlRelaxNGCompareElemDefLists:
3613 * @ctxt: a Relax-NG parser context
3614 * @defs1: the first list of element/attribute defs
3615 * @defs2: the second list of element/attribute defs
3616 *
3617 * Compare the 2 lists of element or attribute definitions. The comparison
3618 * is that if both lists do not accept the same QNames, it returns 1
3619 * If the 2 lists can accept the same QName the comparison returns 0
3620 *
3621 * Returns 1 disttinct, 0 if equal
3622 */
3623static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003624xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3625 xmlRelaxNGDefinePtr *def1,
3626 xmlRelaxNGDefinePtr *def2) {
3627 xmlRelaxNGDefinePtr *basedef2 = def2;
3628
Daniel Veillard154877e2003-01-30 12:17:05 +00003629 if ((def1 == NULL) || (def2 == NULL))
3630 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003631 if ((*def1 == NULL) || (*def2 == NULL))
3632 return(1);
3633 while (*def1 != NULL) {
3634 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003635 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3636 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003637 def2++;
3638 }
3639 def2 = basedef2;
3640 def1++;
3641 }
3642 return(1);
3643}
3644
3645/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003646 * xmlRelaxNGGenerateAttributes:
3647 * @ctxt: a Relax-NG parser context
3648 * @def: the definition definition
3649 *
3650 * Check if the definition can only generate attributes
3651 *
3652 * Returns 1 if yes, 0 if no and -1 in case of error.
3653 */
3654static int
3655xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3656 xmlRelaxNGDefinePtr def) {
3657 xmlRelaxNGDefinePtr parent, cur, tmp;
3658
3659 /*
3660 * Don't run that check in case of error. Infinite recursion
3661 * becomes possible.
3662 */
3663 if (ctxt->nbErrors != 0)
3664 return(-1);
3665
3666 parent = NULL;
3667 cur = def;
3668 while (cur != NULL) {
3669 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3670 (cur->type == XML_RELAXNG_TEXT) ||
3671 (cur->type == XML_RELAXNG_DATATYPE) ||
3672 (cur->type == XML_RELAXNG_PARAM) ||
3673 (cur->type == XML_RELAXNG_LIST) ||
3674 (cur->type == XML_RELAXNG_VALUE) ||
3675 (cur->type == XML_RELAXNG_EMPTY))
3676 return(0);
3677 if ((cur->type == XML_RELAXNG_CHOICE) ||
3678 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3679 (cur->type == XML_RELAXNG_GROUP) ||
3680 (cur->type == XML_RELAXNG_ONEORMORE) ||
3681 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3682 (cur->type == XML_RELAXNG_OPTIONAL) ||
3683 (cur->type == XML_RELAXNG_PARENTREF) ||
3684 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3685 (cur->type == XML_RELAXNG_REF) ||
3686 (cur->type == XML_RELAXNG_DEF)) {
3687 if (cur->content != NULL) {
3688 parent = cur;
3689 cur = cur->content;
3690 tmp = cur;
3691 while (tmp != NULL) {
3692 tmp->parent = parent;
3693 tmp = tmp->next;
3694 }
3695 continue;
3696 }
3697 }
3698 if (cur == def)
3699 break;
3700 if (cur->next != NULL) {
3701 cur = cur->next;
3702 continue;
3703 }
3704 do {
3705 cur = cur->parent;
3706 if (cur == NULL) break;
3707 if (cur == def) return(1);
3708 if (cur->next != NULL) {
3709 cur = cur->next;
3710 break;
3711 }
3712 } while (cur != NULL);
3713 }
3714 return(1);
3715}
3716
3717/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003718 * xmlRelaxNGGetElements:
3719 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003720 * @def: the definition definition
3721 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003722 *
3723 * Compute the list of top elements a definition can generate
3724 *
3725 * Returns a list of elements or NULL if none was found.
3726 */
3727static xmlRelaxNGDefinePtr *
3728xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003729 xmlRelaxNGDefinePtr def,
3730 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003731 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003732 int len = 0;
3733 int max = 0;
3734
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003735 /*
3736 * Don't run that check in case of error. Infinite recursion
3737 * becomes possible.
3738 */
3739 if (ctxt->nbErrors != 0)
3740 return(NULL);
3741
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003742 parent = NULL;
3743 cur = def;
3744 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003745 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3746 (cur->type == XML_RELAXNG_TEXT))) ||
3747 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003748 if (ret == NULL) {
3749 max = 10;
3750 ret = (xmlRelaxNGDefinePtr *)
3751 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3752 if (ret == NULL) {
3753 if (ctxt->error != NULL)
3754 ctxt->error(ctxt->userData,
3755 "Out of memory in element search\n");
3756 ctxt->nbErrors++;
3757 return(NULL);
3758 }
3759 } else if (max <= len) {
3760 max *= 2;
3761 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3762 if (ret == NULL) {
3763 if (ctxt->error != NULL)
3764 ctxt->error(ctxt->userData,
3765 "Out of memory in element search\n");
3766 ctxt->nbErrors++;
3767 return(NULL);
3768 }
3769 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003770 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003771 ret[len] = NULL;
3772 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3773 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3774 (cur->type == XML_RELAXNG_GROUP) ||
3775 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003776 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3777 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003778 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003779 (cur->type == XML_RELAXNG_REF) ||
3780 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003781 /*
3782 * Don't go within elements or attributes or string values.
3783 * Just gather the element top list
3784 */
3785 if (cur->content != NULL) {
3786 parent = cur;
3787 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003788 tmp = cur;
3789 while (tmp != NULL) {
3790 tmp->parent = parent;
3791 tmp = tmp->next;
3792 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003793 continue;
3794 }
3795 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003796 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003797 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003798 if (cur->next != NULL) {
3799 cur = cur->next;
3800 continue;
3801 }
3802 do {
3803 cur = cur->parent;
3804 if (cur == NULL) break;
3805 if (cur == def) return(ret);
3806 if (cur->next != NULL) {
3807 cur = cur->next;
3808 break;
3809 }
3810 } while (cur != NULL);
3811 }
3812 return(ret);
3813}
3814
3815/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003816 * xmlRelaxNGCheckChoiceDeterminism:
3817 * @ctxt: a Relax-NG parser context
3818 * @def: the choice definition
3819 *
3820 * Also used to find indeterministic pattern in choice
3821 */
3822static void
3823xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3824 xmlRelaxNGDefinePtr def) {
3825 xmlRelaxNGDefinePtr **list;
3826 xmlRelaxNGDefinePtr cur;
3827 int nbchild = 0, i, j, ret;
3828 int is_nullable = 0;
3829 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003830 xmlHashTablePtr triage = NULL;
3831 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003832
3833 if ((def == NULL) ||
3834 (def->type != XML_RELAXNG_CHOICE))
3835 return;
3836
Daniel Veillarde063f482003-03-21 16:53:17 +00003837 if (def->dflags & IS_PROCESSED)
3838 return;
3839
Daniel Veillardfd573f12003-03-16 17:52:32 +00003840 /*
3841 * Don't run that check in case of error. Infinite recursion
3842 * becomes possible.
3843 */
3844 if (ctxt->nbErrors != 0)
3845 return;
3846
3847 is_nullable = xmlRelaxNGIsNullable(def);
3848
3849 cur = def->content;
3850 while (cur != NULL) {
3851 nbchild++;
3852 cur = cur->next;
3853 }
3854
3855 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3856 sizeof(xmlRelaxNGDefinePtr *));
3857 if (list == NULL) {
3858 if (ctxt->error != NULL)
3859 ctxt->error(ctxt->userData,
3860 "Out of memory in choice computation\n");
3861 ctxt->nbErrors++;
3862 return;
3863 }
3864 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003865 /*
3866 * a bit strong but safe
3867 */
3868 if (is_nullable == 0) {
3869 triage = xmlHashCreate(10);
3870 } else {
3871 is_triable = 0;
3872 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003873 cur = def->content;
3874 while (cur != NULL) {
3875 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003876 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3877 is_triable = 0;
3878 } else if (is_triable == 1) {
3879 xmlRelaxNGDefinePtr *tmp;
3880 int res;
3881
3882 tmp = list[i];
3883 while ((*tmp != NULL) && (is_triable == 1)) {
3884 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3885 res = xmlHashAddEntry2(triage,
3886 BAD_CAST "#text", NULL,
3887 (void *)cur);
3888 if (res != 0)
3889 is_triable = -1;
3890 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3891 ((*tmp)->name != NULL)) {
3892 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3893 res = xmlHashAddEntry2(triage,
3894 (*tmp)->name, NULL,
3895 (void *)cur);
3896 else
3897 res = xmlHashAddEntry2(triage,
3898 (*tmp)->name, (*tmp)->ns,
3899 (void *)cur);
3900 if (res != 0)
3901 is_triable = -1;
3902 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3903 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3904 res = xmlHashAddEntry2(triage,
3905 BAD_CAST "#any", NULL,
3906 (void *)cur);
3907 else
3908 res = xmlHashAddEntry2(triage,
3909 BAD_CAST "#any", (*tmp)->ns,
3910 (void *)cur);
3911 if (res != 0)
3912 is_triable = -1;
3913 } else {
3914 is_triable = -1;
3915 }
3916 tmp++;
3917 }
3918 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003919 i++;
3920 cur = cur->next;
3921 }
3922
3923 for (i = 0;i < nbchild;i++) {
3924 if (list[i] == NULL)
3925 continue;
3926 for (j = 0;j < i;j++) {
3927 if (list[j] == NULL)
3928 continue;
3929 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3930 if (ret == 0) {
3931 is_indeterminist = 1;
3932 }
3933 }
3934 }
3935 for (i = 0;i < nbchild;i++) {
3936 if (list[i] != NULL)
3937 xmlFree(list[i]);
3938 }
3939
3940 xmlFree(list);
3941 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003942 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003943 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003944 if (is_triable == 1) {
3945 def->dflags |= IS_TRIABLE;
3946 def->data = triage;
3947 } else if (triage != NULL) {
3948 xmlHashFree(triage, NULL);
3949 }
3950 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003951}
3952
3953/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003954 * xmlRelaxNGCheckGroupAttrs:
3955 * @ctxt: a Relax-NG parser context
3956 * @def: the group definition
3957 *
3958 * Detects violations of rule 7.3
3959 */
3960static void
3961xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3962 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003963 xmlRelaxNGDefinePtr **list;
3964 xmlRelaxNGDefinePtr cur;
3965 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003966
3967 if ((def == NULL) ||
3968 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003969 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003970 return;
3971
Daniel Veillarde063f482003-03-21 16:53:17 +00003972 if (def->dflags & IS_PROCESSED)
3973 return;
3974
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003975 /*
3976 * Don't run that check in case of error. Infinite recursion
3977 * becomes possible.
3978 */
3979 if (ctxt->nbErrors != 0)
3980 return;
3981
Daniel Veillardfd573f12003-03-16 17:52:32 +00003982 cur = def->attrs;
3983 while (cur != NULL) {
3984 nbchild++;
3985 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003986 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003987 cur = def->content;
3988 while (cur != NULL) {
3989 nbchild++;
3990 cur = cur->next;
3991 }
3992
3993 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3994 sizeof(xmlRelaxNGDefinePtr *));
3995 if (list == NULL) {
3996 if (ctxt->error != NULL)
3997 ctxt->error(ctxt->userData,
3998 "Out of memory in group computation\n");
3999 ctxt->nbErrors++;
4000 return;
4001 }
4002 i = 0;
4003 cur = def->attrs;
4004 while (cur != NULL) {
4005 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4006 i++;
4007 cur = cur->next;
4008 }
4009 cur = def->content;
4010 while (cur != NULL) {
4011 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4012 i++;
4013 cur = cur->next;
4014 }
4015
4016 for (i = 0;i < nbchild;i++) {
4017 if (list[i] == NULL)
4018 continue;
4019 for (j = 0;j < i;j++) {
4020 if (list[j] == NULL)
4021 continue;
4022 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4023 if (ret == 0) {
4024 if (ctxt->error != NULL)
4025 ctxt->error(ctxt->userData,
4026 "Attributes conflicts in group\n");
4027 ctxt->nbErrors++;
4028 }
4029 }
4030 }
4031 for (i = 0;i < nbchild;i++) {
4032 if (list[i] != NULL)
4033 xmlFree(list[i]);
4034 }
4035
4036 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004037 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004038}
4039
4040/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004041 * xmlRelaxNGComputeInterleaves:
4042 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004043 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004044 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004045 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004046 * A lot of work for preprocessing interleave definitions
4047 * is potentially needed to get a decent execution speed at runtime
4048 * - trying to get a total order on the element nodes generated
4049 * by the interleaves, order the list of interleave definitions
4050 * following that order.
4051 * - if <text/> is used to handle mixed content, it is better to
4052 * flag this in the define and simplify the runtime checking
4053 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004054 */
4055static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004056xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4057 xmlRelaxNGParserCtxtPtr ctxt,
4058 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004059 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004060
Daniel Veillardfd573f12003-03-16 17:52:32 +00004061 xmlRelaxNGPartitionPtr partitions = NULL;
4062 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4063 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004064 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004065 int nbgroups = 0;
4066 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004067 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004068 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004069
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004070 /*
4071 * Don't run that check in case of error. Infinite recursion
4072 * becomes possible.
4073 */
4074 if (ctxt->nbErrors != 0)
4075 return;
4076
Daniel Veillardfd573f12003-03-16 17:52:32 +00004077#ifdef DEBUG_INTERLEAVE
4078 xmlGenericError(xmlGenericErrorContext,
4079 "xmlRelaxNGComputeInterleaves(%s)\n",
4080 name);
4081#endif
4082 cur = def->content;
4083 while (cur != NULL) {
4084 nbchild++;
4085 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004086 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004087
4088#ifdef DEBUG_INTERLEAVE
4089 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4090#endif
4091 groups = (xmlRelaxNGInterleaveGroupPtr *)
4092 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4093 if (groups == NULL)
4094 goto error;
4095 cur = def->content;
4096 while (cur != NULL) {
4097 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4098 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4099 if (groups[nbgroups] == NULL)
4100 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004101 if (cur->type == XML_RELAXNG_TEXT)
4102 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004103 groups[nbgroups]->rule = cur;
4104 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4105 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4106 nbgroups++;
4107 cur = cur->next;
4108 }
4109#ifdef DEBUG_INTERLEAVE
4110 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4111#endif
4112
4113 /*
4114 * Let's check that all rules makes a partitions according to 7.4
4115 */
4116 partitions = (xmlRelaxNGPartitionPtr)
4117 xmlMalloc(sizeof(xmlRelaxNGPartition));
4118 if (partitions == NULL)
4119 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004120 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004121 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004122 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004123 for (i = 0;i < nbgroups;i++) {
4124 group = groups[i];
4125 for (j = i+1;j < nbgroups;j++) {
4126 if (groups[j] == NULL)
4127 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004128
Daniel Veillardfd573f12003-03-16 17:52:32 +00004129 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4130 groups[j]->defs);
4131 if (ret == 0) {
4132 if (ctxt->error != NULL)
4133 ctxt->error(ctxt->userData,
4134 "Element or text conflicts in interleave\n");
4135 ctxt->nbErrors++;
4136 }
4137 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4138 groups[j]->attrs);
4139 if (ret == 0) {
4140 if (ctxt->error != NULL)
4141 ctxt->error(ctxt->userData,
4142 "Attributes conflicts in interleave\n");
4143 ctxt->nbErrors++;
4144 }
4145 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004146 tmp = group->defs;
4147 if ((tmp != NULL) && (*tmp != NULL)) {
4148 while (*tmp != NULL) {
4149 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4150 res = xmlHashAddEntry2(partitions->triage,
4151 BAD_CAST "#text", NULL,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004152 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004153 if (res != 0)
4154 is_determinist = -1;
4155 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4156 ((*tmp)->name != NULL)) {
4157 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4158 res = xmlHashAddEntry2(partitions->triage,
4159 (*tmp)->name, NULL,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004160 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004161 else
4162 res = xmlHashAddEntry2(partitions->triage,
4163 (*tmp)->name, (*tmp)->ns,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004164 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004165 if (res != 0)
4166 is_determinist = -1;
4167 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4168 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4169 res = xmlHashAddEntry2(partitions->triage,
4170 BAD_CAST "#any", NULL,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004171 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004172 else
4173 res = xmlHashAddEntry2(partitions->triage,
4174 BAD_CAST "#any", (*tmp)->ns,
Daniel Veillard34ba3872003-07-15 13:34:05 +00004175 (void *)(long)(i + 1));
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004176 if ((*tmp)->nameClass != NULL)
4177 is_determinist = 2;
4178 if (res != 0)
4179 is_determinist = -1;
4180 } else {
4181 is_determinist = -1;
4182 }
4183 tmp++;
4184 }
4185 } else {
4186 is_determinist = 0;
4187 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004188 }
4189 partitions->groups = groups;
4190
4191 /*
4192 * and save the partition list back in the def
4193 */
4194 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004195 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00004196 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004197 if (is_determinist == 1)
4198 partitions->flags = IS_DETERMINIST;
4199 if (is_determinist == 2)
4200 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004201 return;
4202
4203error:
4204 if (ctxt->error != NULL)
4205 ctxt->error(ctxt->userData,
4206 "Out of memory in interleave computation\n");
4207 ctxt->nbErrors++;
4208 if (groups != NULL) {
4209 for (i = 0;i < nbgroups;i++)
4210 if (groups[i] != NULL) {
4211 if (groups[i]->defs != NULL)
4212 xmlFree(groups[i]->defs);
4213 xmlFree(groups[i]);
4214 }
4215 xmlFree(groups);
4216 }
4217 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004218}
4219
4220/**
4221 * xmlRelaxNGParseInterleave:
4222 * @ctxt: a Relax-NG parser context
4223 * @node: the data node.
4224 *
4225 * parse the content of a RelaxNG interleave node.
4226 *
4227 * Returns the definition pointer or NULL in case of error
4228 */
4229static xmlRelaxNGDefinePtr
4230xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4231 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004232 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004233 xmlNodePtr child;
4234
Daniel Veillardfd573f12003-03-16 17:52:32 +00004235 def = xmlRelaxNGNewDefine(ctxt, node);
4236 if (def == NULL) {
4237 return(NULL);
4238 }
4239 def->type = XML_RELAXNG_INTERLEAVE;
4240
4241 if (ctxt->interleaves == NULL)
4242 ctxt->interleaves = xmlHashCreate(10);
4243 if (ctxt->interleaves == NULL) {
4244 if (ctxt->error != NULL)
4245 ctxt->error(ctxt->userData,
4246 "Failed to create interleaves hash table\n");
4247 ctxt->nbErrors++;
4248 } else {
4249 char name[32];
4250
4251 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4252 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4253 if (ctxt->error != NULL)
4254 ctxt->error(ctxt->userData,
4255 "Failed to add %s to hash table\n", name);
4256 ctxt->nbErrors++;
4257 }
4258 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004259 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004260 if (child == NULL) {
4261 if (ctxt->error != NULL)
4262 ctxt->error(ctxt->userData, "Element interleave is empty\n");
4263 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004264 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004265 while (child != NULL) {
4266 if (IS_RELAXNG(child, "element")) {
4267 cur = xmlRelaxNGParseElement(ctxt, child);
4268 } else {
4269 cur = xmlRelaxNGParsePattern(ctxt, child);
4270 }
4271 if (cur != NULL) {
4272 cur->parent = def;
4273 if (last == NULL) {
4274 def->content = last = cur;
4275 } else {
4276 last->next = cur;
4277 last = cur;
4278 }
4279 }
4280 child = child->next;
4281 }
4282
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004283 return(def);
4284}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004285
4286/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004287 * xmlRelaxNGParseInclude:
4288 * @ctxt: a Relax-NG parser context
4289 * @node: the include node
4290 *
4291 * Integrate the content of an include node in the current grammar
4292 *
4293 * Returns 0 in case of success or -1 in case of error
4294 */
4295static int
4296xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4297 xmlRelaxNGIncludePtr incl;
4298 xmlNodePtr root;
4299 int ret = 0, tmp;
4300
4301 incl = node->_private;
4302 if (incl == NULL) {
4303 if (ctxt->error != NULL)
4304 ctxt->error(ctxt->userData,
4305 "Include node has no data\n");
4306 ctxt->nbErrors++;
4307 return(-1);
4308 }
4309 root = xmlDocGetRootElement(incl->doc);
4310 if (root == NULL) {
4311 if (ctxt->error != NULL)
4312 ctxt->error(ctxt->userData,
4313 "Include document is empty\n");
4314 ctxt->nbErrors++;
4315 return(-1);
4316 }
4317 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4318 if (ctxt->error != NULL)
4319 ctxt->error(ctxt->userData,
4320 "Include document root is not a grammar\n");
4321 ctxt->nbErrors++;
4322 return(-1);
4323 }
4324
4325 /*
4326 * Merge the definition from both the include and the internal list
4327 */
4328 if (root->children != NULL) {
4329 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4330 if (tmp != 0)
4331 ret = -1;
4332 }
4333 if (node->children != NULL) {
4334 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4335 if (tmp != 0)
4336 ret = -1;
4337 }
4338 return(ret);
4339}
4340
4341/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004342 * xmlRelaxNGParseDefine:
4343 * @ctxt: a Relax-NG parser context
4344 * @node: the define node
4345 *
4346 * parse the content of a RelaxNG define element node.
4347 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004348 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004349 */
4350static int
4351xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4352 xmlChar *name;
4353 int ret = 0, tmp;
4354 xmlRelaxNGDefinePtr def;
4355 const xmlChar *olddefine;
4356
4357 name = xmlGetProp(node, BAD_CAST "name");
4358 if (name == NULL) {
4359 if (ctxt->error != NULL)
4360 ctxt->error(ctxt->userData,
4361 "define has no name\n");
4362 ctxt->nbErrors++;
4363 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004364 xmlRelaxNGNormExtSpace(name);
4365 if (xmlValidateNCName(name, 0)) {
4366 if (ctxt->error != NULL)
4367 ctxt->error(ctxt->userData,
4368 "define name '%s' is not an NCName\n",
4369 name);
4370 ctxt->nbErrors++;
4371 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004372 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004373 if (def == NULL) {
4374 xmlFree(name);
4375 return(-1);
4376 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004377 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004378 def->name = name;
4379 if (node->children == NULL) {
4380 if (ctxt->error != NULL)
4381 ctxt->error(ctxt->userData,
4382 "define has no children\n");
4383 ctxt->nbErrors++;
4384 } else {
4385 olddefine = ctxt->define;
4386 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00004387 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004388 ctxt->define = olddefine;
4389 }
4390 if (ctxt->grammar->defs == NULL)
4391 ctxt->grammar->defs = xmlHashCreate(10);
4392 if (ctxt->grammar->defs == NULL) {
4393 if (ctxt->error != NULL)
4394 ctxt->error(ctxt->userData,
4395 "Could not create definition hash\n");
4396 ctxt->nbErrors++;
4397 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004398 } else {
4399 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4400 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00004401 xmlRelaxNGDefinePtr prev;
4402
4403 prev = xmlHashLookup(ctxt->grammar->defs, name);
4404 if (prev == NULL) {
4405 if (ctxt->error != NULL)
4406 ctxt->error(ctxt->userData,
4407 "Internal error on define aggregation of %s\n",
4408 name);
4409 ctxt->nbErrors++;
4410 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00004411 } else {
4412 while (prev->nextHash != NULL)
4413 prev = prev->nextHash;
4414 prev->nextHash = def;
4415 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004416 }
4417 }
4418 }
4419 return(ret);
4420}
4421
4422/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004423 * xmlRelaxNGProcessExternalRef:
4424 * @ctxt: the parser context
4425 * @node: the externlRef node
4426 *
4427 * Process and compile an externlRef node
4428 *
4429 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4430 */
4431static xmlRelaxNGDefinePtr
4432xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4433 xmlRelaxNGDocumentPtr docu;
4434 xmlNodePtr root, tmp;
4435 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004436 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004437 xmlRelaxNGDefinePtr def;
4438
4439 docu = node->_private;
4440 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004441 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004442 if (def == NULL)
4443 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004444 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004445
4446 if (docu->content == NULL) {
4447 /*
4448 * Then do the parsing for good
4449 */
4450 root = xmlDocGetRootElement(docu->doc);
4451 if (root == NULL) {
4452 if (ctxt->error != NULL)
4453 ctxt->error(ctxt->userData,
4454 "xmlRelaxNGParse: %s is empty\n",
4455 ctxt->URL);
4456 ctxt->nbErrors++;
4457 return (NULL);
4458 }
4459 /*
4460 * ns transmission rules
4461 */
4462 ns = xmlGetProp(root, BAD_CAST "ns");
4463 if (ns == NULL) {
4464 tmp = node;
4465 while ((tmp != NULL) &&
4466 (tmp->type == XML_ELEMENT_NODE)) {
4467 ns = xmlGetProp(tmp, BAD_CAST "ns");
4468 if (ns != NULL) {
4469 break;
4470 }
4471 tmp = tmp->parent;
4472 }
4473 if (ns != NULL) {
4474 xmlSetProp(root, BAD_CAST "ns", ns);
4475 newNs = 1;
4476 xmlFree(ns);
4477 }
4478 } else {
4479 xmlFree(ns);
4480 }
4481
4482 /*
4483 * Parsing to get a precompiled schemas.
4484 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004485 oldflags = ctxt->flags;
4486 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004487 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004488 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004489 if ((docu->schema != NULL) &&
4490 (docu->schema->topgrammar != NULL)) {
4491 docu->content = docu->schema->topgrammar->start;
4492 }
4493
4494 /*
4495 * the externalRef may be reused in a different ns context
4496 */
4497 if (newNs == 1) {
4498 xmlUnsetProp(root, BAD_CAST "ns");
4499 }
4500 }
4501 def->content = docu->content;
4502 } else {
4503 def = NULL;
4504 }
4505 return(def);
4506}
4507
4508/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004509 * xmlRelaxNGParsePattern:
4510 * @ctxt: a Relax-NG parser context
4511 * @node: the pattern node.
4512 *
4513 * parse the content of a RelaxNG pattern node.
4514 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004515 * Returns the definition pointer or NULL in case of error or if no
4516 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004517 */
4518static xmlRelaxNGDefinePtr
4519xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4520 xmlRelaxNGDefinePtr def = NULL;
4521
Daniel Veillardd2298792003-02-14 16:54:11 +00004522 if (node == NULL) {
4523 return(NULL);
4524 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004525 if (IS_RELAXNG(node, "element")) {
4526 def = xmlRelaxNGParseElement(ctxt, node);
4527 } else if (IS_RELAXNG(node, "attribute")) {
4528 def = xmlRelaxNGParseAttribute(ctxt, node);
4529 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004530 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004531 if (def == NULL)
4532 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004533 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004534 if (node->children != NULL) {
4535 if (ctxt->error != NULL)
4536 ctxt->error(ctxt->userData, "empty: had a child node\n");
4537 ctxt->nbErrors++;
4538 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004539 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004540 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004541 if (def == NULL)
4542 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004543 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004544 if (node->children != NULL) {
4545 if (ctxt->error != NULL)
4546 ctxt->error(ctxt->userData, "text: had a child node\n");
4547 ctxt->nbErrors++;
4548 }
4549 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004550 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004551 if (def == NULL)
4552 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004553 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004554 if (node->children == NULL) {
4555 if (ctxt->error != NULL)
4556 ctxt->error(ctxt->userData,
4557 "Element %s is empty\n", node->name);
4558 ctxt->nbErrors++;
4559 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004560 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004561 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004562 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004563 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004564 if (def == NULL)
4565 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004566 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004567 if (node->children == NULL) {
4568 if (ctxt->error != NULL)
4569 ctxt->error(ctxt->userData,
4570 "Element %s is empty\n", node->name);
4571 ctxt->nbErrors++;
4572 } else {
4573 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4574 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004575 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004576 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004577 if (def == NULL)
4578 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004579 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004580 if (node->children == NULL) {
4581 if (ctxt->error != NULL)
4582 ctxt->error(ctxt->userData,
4583 "Element %s is empty\n", node->name);
4584 ctxt->nbErrors++;
4585 } else {
4586 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4587 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004588 } else if (IS_RELAXNG(node, "choice")) {
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_CHOICE;
4593 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 {
4599 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4600 }
4601 } else if (IS_RELAXNG(node, "group")) {
4602 def = xmlRelaxNGNewDefine(ctxt, node);
4603 if (def == NULL)
4604 return(NULL);
4605 def->type = XML_RELAXNG_GROUP;
4606 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, 0);
4613 }
4614 } else if (IS_RELAXNG(node, "ref")) {
4615 def = xmlRelaxNGNewDefine(ctxt, node);
4616 if (def == NULL)
4617 return(NULL);
4618 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004619 def->name = xmlGetProp(node, BAD_CAST "name");
4620 if (def->name == NULL) {
4621 if (ctxt->error != NULL)
4622 ctxt->error(ctxt->userData,
4623 "ref has no name\n");
4624 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004625 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004626 xmlRelaxNGNormExtSpace(def->name);
4627 if (xmlValidateNCName(def->name, 0)) {
4628 if (ctxt->error != NULL)
4629 ctxt->error(ctxt->userData,
4630 "ref name '%s' is not an NCName\n",
4631 def->name);
4632 ctxt->nbErrors++;
4633 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004634 }
4635 if (node->children != NULL) {
4636 if (ctxt->error != NULL)
4637 ctxt->error(ctxt->userData,
4638 "ref is not empty\n");
4639 ctxt->nbErrors++;
4640 }
4641 if (ctxt->grammar->refs == NULL)
4642 ctxt->grammar->refs = xmlHashCreate(10);
4643 if (ctxt->grammar->refs == NULL) {
4644 if (ctxt->error != NULL)
4645 ctxt->error(ctxt->userData,
4646 "Could not create references hash\n");
4647 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004648 def = NULL;
4649 } else {
4650 int tmp;
4651
4652 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4653 if (tmp < 0) {
4654 xmlRelaxNGDefinePtr prev;
4655
4656 prev = (xmlRelaxNGDefinePtr)
4657 xmlHashLookup(ctxt->grammar->refs, def->name);
4658 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004659 if (def->name != NULL) {
4660 if (ctxt->error != NULL)
4661 ctxt->error(ctxt->userData,
4662 "Error refs definitions '%s'\n",
4663 def->name);
4664 } else {
4665 if (ctxt->error != NULL)
4666 ctxt->error(ctxt->userData,
4667 "Error refs definitions\n");
4668 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004669 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004670 def = NULL;
4671 } else {
4672 def->nextHash = prev->nextHash;
4673 prev->nextHash = def;
4674 }
4675 }
4676 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004677 } else if (IS_RELAXNG(node, "data")) {
4678 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004679 } else if (IS_RELAXNG(node, "value")) {
4680 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004681 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004682 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004683 if (def == NULL)
4684 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004685 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004686 if (node->children == NULL) {
4687 if (ctxt->error != NULL)
4688 ctxt->error(ctxt->userData,
4689 "Element %s is empty\n", node->name);
4690 ctxt->nbErrors++;
4691 } else {
4692 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4693 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004694 } else if (IS_RELAXNG(node, "interleave")) {
4695 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004696 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004697 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004698 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004699 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004700 if (def == NULL)
4701 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004702 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004703 if (node->children != NULL) {
4704 if (ctxt->error != NULL)
4705 ctxt->error(ctxt->userData,
4706 "xmlRelaxNGParse: notAllowed element is not empty\n");
4707 ctxt->nbErrors++;
4708 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004709 } else if (IS_RELAXNG(node, "grammar")) {
4710 xmlRelaxNGGrammarPtr grammar, old;
4711 xmlRelaxNGGrammarPtr oldparent;
4712
Daniel Veillardc482e262003-02-26 14:48:48 +00004713#ifdef DEBUG_GRAMMAR
4714 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4715#endif
4716
Daniel Veillard419a7682003-02-03 23:22:49 +00004717 oldparent = ctxt->parentgrammar;
4718 old = ctxt->grammar;
4719 ctxt->parentgrammar = old;
4720 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4721 if (old != NULL) {
4722 ctxt->grammar = old;
4723 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004724#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004725 if (grammar != NULL) {
4726 grammar->next = old->next;
4727 old->next = grammar;
4728 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004729#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004730 }
4731 if (grammar != NULL)
4732 def = grammar->start;
4733 else
4734 def = NULL;
4735 } else if (IS_RELAXNG(node, "parentRef")) {
4736 if (ctxt->parentgrammar == NULL) {
4737 if (ctxt->error != NULL)
4738 ctxt->error(ctxt->userData,
4739 "Use of parentRef without a parent grammar\n");
4740 ctxt->nbErrors++;
4741 return(NULL);
4742 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004743 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004744 if (def == NULL)
4745 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004746 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004747 def->name = xmlGetProp(node, BAD_CAST "name");
4748 if (def->name == NULL) {
4749 if (ctxt->error != NULL)
4750 ctxt->error(ctxt->userData,
4751 "parentRef has no name\n");
4752 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004753 } else {
4754 xmlRelaxNGNormExtSpace(def->name);
4755 if (xmlValidateNCName(def->name, 0)) {
4756 if (ctxt->error != NULL)
4757 ctxt->error(ctxt->userData,
4758 "parentRef name '%s' is not an NCName\n",
4759 def->name);
4760 ctxt->nbErrors++;
4761 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004762 }
4763 if (node->children != NULL) {
4764 if (ctxt->error != NULL)
4765 ctxt->error(ctxt->userData,
4766 "parentRef is not empty\n");
4767 ctxt->nbErrors++;
4768 }
4769 if (ctxt->parentgrammar->refs == NULL)
4770 ctxt->parentgrammar->refs = xmlHashCreate(10);
4771 if (ctxt->parentgrammar->refs == NULL) {
4772 if (ctxt->error != NULL)
4773 ctxt->error(ctxt->userData,
4774 "Could not create references hash\n");
4775 ctxt->nbErrors++;
4776 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004777 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004778 int tmp;
4779
4780 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4781 if (tmp < 0) {
4782 xmlRelaxNGDefinePtr prev;
4783
4784 prev = (xmlRelaxNGDefinePtr)
4785 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4786 if (prev == NULL) {
4787 if (ctxt->error != NULL)
4788 ctxt->error(ctxt->userData,
4789 "Internal error parentRef definitions '%s'\n",
4790 def->name);
4791 ctxt->nbErrors++;
4792 def = NULL;
4793 } else {
4794 def->nextHash = prev->nextHash;
4795 prev->nextHash = def;
4796 }
4797 }
4798 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004799 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004800 if (node->children == NULL) {
4801 if (ctxt->error != NULL)
4802 ctxt->error(ctxt->userData,
4803 "Mixed is empty\n");
4804 ctxt->nbErrors++;
4805 def = NULL;
4806 } else {
4807 def = xmlRelaxNGParseInterleave(ctxt, node);
4808 if (def != NULL) {
4809 xmlRelaxNGDefinePtr tmp;
4810
4811 if ((def->content != NULL) && (def->content->next != NULL)) {
4812 tmp = xmlRelaxNGNewDefine(ctxt, node);
4813 if (tmp != NULL) {
4814 tmp->type = XML_RELAXNG_GROUP;
4815 tmp->content = def->content;
4816 def->content = tmp;
4817 }
4818 }
4819
4820 tmp = xmlRelaxNGNewDefine(ctxt, node);
4821 if (tmp == NULL)
4822 return(def);
4823 tmp->type = XML_RELAXNG_TEXT;
4824 tmp->next = def->content;
4825 def->content = tmp;
4826 }
4827 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004828 } else {
4829 if (ctxt->error != NULL)
4830 ctxt->error(ctxt->userData,
4831 "Unexpected node %s is not a pattern\n",
4832 node->name);
4833 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004834 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004835 }
4836 return(def);
4837}
4838
4839/**
4840 * xmlRelaxNGParseAttribute:
4841 * @ctxt: a Relax-NG parser context
4842 * @node: the element node
4843 *
4844 * parse the content of a RelaxNG attribute node.
4845 *
4846 * Returns the definition pointer or NULL in case of error.
4847 */
4848static xmlRelaxNGDefinePtr
4849xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004850 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004851 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004852 int old_flags;
4853
Daniel Veillardfd573f12003-03-16 17:52:32 +00004854 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004855 if (ret == NULL)
4856 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004857 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004858 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004859 child = node->children;
4860 if (child == NULL) {
4861 if (ctxt->error != NULL)
4862 ctxt->error(ctxt->userData,
4863 "xmlRelaxNGParseattribute: attribute has no children\n");
4864 ctxt->nbErrors++;
4865 return(ret);
4866 }
4867 old_flags = ctxt->flags;
4868 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004869 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4870 if (cur != NULL)
4871 child = child->next;
4872
Daniel Veillardd2298792003-02-14 16:54:11 +00004873 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004874 cur = xmlRelaxNGParsePattern(ctxt, child);
4875 if (cur != NULL) {
4876 switch (cur->type) {
4877 case XML_RELAXNG_EMPTY:
4878 case XML_RELAXNG_NOT_ALLOWED:
4879 case XML_RELAXNG_TEXT:
4880 case XML_RELAXNG_ELEMENT:
4881 case XML_RELAXNG_DATATYPE:
4882 case XML_RELAXNG_VALUE:
4883 case XML_RELAXNG_LIST:
4884 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004885 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004886 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004887 case XML_RELAXNG_DEF:
4888 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004889 case XML_RELAXNG_ZEROORMORE:
4890 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004891 case XML_RELAXNG_CHOICE:
4892 case XML_RELAXNG_GROUP:
4893 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004894 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004895 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004896 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004897 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004898 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004899 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004900 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004901 if (ctxt->error != NULL)
4902 ctxt->error(ctxt->userData,
4903 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004904 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004905 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004906 case XML_RELAXNG_NOOP:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004907 if (ctxt->error != NULL)
4908 ctxt->error(ctxt->userData,
Daniel Veillardac297932003-04-17 12:55:35 +00004909 "RNG Internal error, noop found in attribute\n");
Daniel Veillard77648bb2003-02-20 15:03:22 +00004910 ctxt->nbErrors++;
4911 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004912 }
4913 }
4914 child = child->next;
4915 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004916 if (child != NULL) {
4917 if (ctxt->error != NULL)
4918 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4919 ctxt->nbErrors++;
4920 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004921 ctxt->flags = old_flags;
4922 return(ret);
4923}
4924
4925/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004926 * xmlRelaxNGParseExceptNameClass:
4927 * @ctxt: a Relax-NG parser context
4928 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004929 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004930 *
4931 * parse the content of a RelaxNG nameClass node.
4932 *
4933 * Returns the definition pointer or NULL in case of error.
4934 */
4935static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004936xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4937 xmlNodePtr node, int attr) {
4938 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4939 xmlNodePtr child;
4940
Daniel Veillardd2298792003-02-14 16:54:11 +00004941 if (!IS_RELAXNG(node, "except")) {
4942 if (ctxt->error != NULL)
4943 ctxt->error(ctxt->userData,
4944 "Expecting an except node\n");
4945 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004946 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004947 }
4948 if (node->next != NULL) {
4949 if (ctxt->error != NULL)
4950 ctxt->error(ctxt->userData,
4951 "exceptNameClass allows only a single except node\n");
4952 ctxt->nbErrors++;
4953 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004954 if (node->children == NULL) {
4955 if (ctxt->error != NULL)
4956 ctxt->error(ctxt->userData,
4957 "except has no content\n");
4958 ctxt->nbErrors++;
4959 return(NULL);
4960 }
4961
Daniel Veillardfd573f12003-03-16 17:52:32 +00004962 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004963 if (ret == NULL)
4964 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004965 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004966 child = node->children;
4967 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004968 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004969 if (cur == NULL)
4970 break;
4971 if (attr)
4972 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004973 else
4974 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004975
Daniel Veillard419a7682003-02-03 23:22:49 +00004976 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004977 if (last == NULL) {
4978 ret->content = cur;
4979 } else {
4980 last->next = cur;
4981 }
4982 last = cur;
4983 }
4984 child = child->next;
4985 }
4986
4987 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004988}
4989
4990/**
4991 * xmlRelaxNGParseNameClass:
4992 * @ctxt: a Relax-NG parser context
4993 * @node: the nameClass node
4994 * @def: the current definition
4995 *
4996 * parse the content of a RelaxNG nameClass node.
4997 *
4998 * Returns the definition pointer or NULL in case of error.
4999 */
5000static xmlRelaxNGDefinePtr
5001xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5002 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005003 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005004 xmlChar *val;
5005
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005006 ret = def;
5007 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5008 (IS_RELAXNG(node, "nsName"))) {
5009 if ((def->type != XML_RELAXNG_ELEMENT) &&
5010 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005011 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005012 if (ret == NULL)
5013 return(NULL);
5014 ret->parent = def;
5015 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5016 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005017 else
5018 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005019 }
5020 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005021 if (IS_RELAXNG(node, "name")) {
5022 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00005023 xmlRelaxNGNormExtSpace(val);
5024 if (xmlValidateNCName(val, 0)) {
5025 if (ctxt->error != NULL) {
5026 if (node->parent != NULL)
5027 ctxt->error(ctxt->userData,
5028 "Element %s name '%s' is not an NCName\n",
5029 node->parent->name, val);
5030 else
5031 ctxt->error(ctxt->userData,
5032 "name '%s' is not an NCName\n",
5033 val);
5034 }
5035 ctxt->nbErrors++;
5036 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005037 ret->name = val;
5038 val = xmlGetProp(node, BAD_CAST "ns");
5039 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00005040 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5041 (val != NULL) &&
5042 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5043 ctxt->error(ctxt->userData,
5044 "Attribute with namespace '%s' is not allowed\n",
5045 val);
5046 ctxt->nbErrors++;
5047 }
5048 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5049 (val != NULL) &&
5050 (val[0] == 0) &&
5051 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5052 ctxt->error(ctxt->userData,
5053 "Attribute with QName 'xmlns' is not allowed\n",
5054 val);
5055 ctxt->nbErrors++;
5056 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005057 } else if (IS_RELAXNG(node, "anyName")) {
5058 ret->name = NULL;
5059 ret->ns = NULL;
5060 if (node->children != NULL) {
5061 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005062 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5063 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005064 }
5065 } else if (IS_RELAXNG(node, "nsName")) {
5066 ret->name = NULL;
5067 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5068 if (ret->ns == NULL) {
5069 if (ctxt->error != NULL)
5070 ctxt->error(ctxt->userData,
5071 "nsName has no ns attribute\n");
5072 ctxt->nbErrors++;
5073 }
Daniel Veillard416589a2003-02-17 17:25:42 +00005074 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5075 (ret->ns != NULL) &&
5076 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5077 ctxt->error(ctxt->userData,
5078 "Attribute with namespace '%s' is not allowed\n",
5079 ret->ns);
5080 ctxt->nbErrors++;
5081 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005082 if (node->children != NULL) {
5083 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005084 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5085 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005086 }
5087 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005088 xmlNodePtr child;
5089 xmlRelaxNGDefinePtr last = NULL;
5090
5091 ret = xmlRelaxNGNewDefine(ctxt, node);
5092 if (ret == NULL)
5093 return(NULL);
5094 ret->parent = def;
5095 ret->type = XML_RELAXNG_CHOICE;
5096
Daniel Veillardd2298792003-02-14 16:54:11 +00005097 if (node->children == NULL) {
5098 if (ctxt->error != NULL)
5099 ctxt->error(ctxt->userData,
5100 "Element choice is empty\n");
5101 ctxt->nbErrors++;
5102 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005103
5104 child = node->children;
5105 while (child != NULL) {
5106 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5107 if (tmp != NULL) {
5108 if (last == NULL) {
5109 last = ret->nameClass = tmp;
5110 } else {
5111 last->next = tmp;
5112 last = tmp;
5113 }
5114 }
5115 child = child->next;
5116 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005117 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005118 } else {
5119 if (ctxt->error != NULL)
5120 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00005121 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005122 node->name);
5123 ctxt->nbErrors++;
5124 return(NULL);
5125 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005126 if (ret != def) {
5127 if (def->nameClass == NULL) {
5128 def->nameClass = ret;
5129 } else {
5130 tmp = def->nameClass;
5131 while (tmp->next != NULL) {
5132 tmp = tmp->next;
5133 }
5134 tmp->next = ret;
5135 }
5136 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005137 return(ret);
5138}
5139
5140/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005141 * xmlRelaxNGParseElement:
5142 * @ctxt: a Relax-NG parser context
5143 * @node: the element node
5144 *
5145 * parse the content of a RelaxNG element node.
5146 *
5147 * Returns the definition pointer or NULL in case of error.
5148 */
5149static xmlRelaxNGDefinePtr
5150xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5151 xmlRelaxNGDefinePtr ret, cur, last;
5152 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005153 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005154
Daniel Veillardfd573f12003-03-16 17:52:32 +00005155 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005156 if (ret == NULL)
5157 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005158 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005159 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005160 child = node->children;
5161 if (child == NULL) {
5162 if (ctxt->error != NULL)
5163 ctxt->error(ctxt->userData,
5164 "xmlRelaxNGParseElement: element has no children\n");
5165 ctxt->nbErrors++;
5166 return(ret);
5167 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005168 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5169 if (cur != NULL)
5170 child = child->next;
5171
Daniel Veillard6eadf632003-01-23 18:29:16 +00005172 if (child == NULL) {
5173 if (ctxt->error != NULL)
5174 ctxt->error(ctxt->userData,
5175 "xmlRelaxNGParseElement: element has no content\n");
5176 ctxt->nbErrors++;
5177 return(ret);
5178 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005179 olddefine = ctxt->define;
5180 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005181 last = NULL;
5182 while (child != NULL) {
5183 cur = xmlRelaxNGParsePattern(ctxt, child);
5184 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005185 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005186 switch (cur->type) {
5187 case XML_RELAXNG_EMPTY:
5188 case XML_RELAXNG_NOT_ALLOWED:
5189 case XML_RELAXNG_TEXT:
5190 case XML_RELAXNG_ELEMENT:
5191 case XML_RELAXNG_DATATYPE:
5192 case XML_RELAXNG_VALUE:
5193 case XML_RELAXNG_LIST:
5194 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00005195 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005196 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005197 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005198 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005199 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005200 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005201 case XML_RELAXNG_CHOICE:
5202 case XML_RELAXNG_GROUP:
5203 case XML_RELAXNG_INTERLEAVE:
5204 if (last == NULL) {
5205 ret->content = last = cur;
5206 } else {
5207 if ((last->type == XML_RELAXNG_ELEMENT) &&
5208 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005209 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005210 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005211 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005212 ret->content->content = last;
5213 } else {
5214 ret->content = last;
5215 }
5216 }
5217 last->next = cur;
5218 last = cur;
5219 }
5220 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005221 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardce192eb2003-04-16 15:58:05 +00005222 /* HERE !!! */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005223 cur->next = ret->attrs;
5224 ret->attrs = cur;
5225 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005226 case XML_RELAXNG_START:
Daniel Veillardac297932003-04-17 12:55:35 +00005227 if (ctxt->error != NULL)
5228 ctxt->error(ctxt->userData,
5229 "RNG Internal error, start found in element\n");
5230 ctxt->nbErrors++;
5231 break;
Daniel Veillard8fe98712003-02-19 00:19:14 +00005232 case XML_RELAXNG_PARAM:
Daniel Veillardac297932003-04-17 12:55:35 +00005233 if (ctxt->error != NULL)
5234 ctxt->error(ctxt->userData,
5235 "RNG Internal error, param found in element\n");
5236 ctxt->nbErrors++;
5237 break;
Daniel Veillard144fae12003-02-03 13:17:57 +00005238 case XML_RELAXNG_EXCEPT:
Daniel Veillardac297932003-04-17 12:55:35 +00005239 if (ctxt->error != NULL)
5240 ctxt->error(ctxt->userData,
5241 "RNG Internal error, except found in element\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005242 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005243 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00005244 case XML_RELAXNG_NOOP:
Daniel Veillard77648bb2003-02-20 15:03:22 +00005245 if (ctxt->error != NULL)
5246 ctxt->error(ctxt->userData,
Daniel Veillardac297932003-04-17 12:55:35 +00005247 "RNG Internal error, noop found in element\n");
Daniel Veillard77648bb2003-02-20 15:03:22 +00005248 ctxt->nbErrors++;
5249 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005250 }
5251 }
5252 child = child->next;
5253 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005254 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005255 return(ret);
5256}
5257
5258/**
5259 * xmlRelaxNGParsePatterns:
5260 * @ctxt: a Relax-NG parser context
5261 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005262 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005263 *
5264 * parse the content of a RelaxNG start node.
5265 *
5266 * Returns the definition pointer or NULL in case of error.
5267 */
5268static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005269xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5270 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005271 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005272
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005273 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005274 while (nodes != NULL) {
5275 if (IS_RELAXNG(nodes, "element")) {
5276 cur = xmlRelaxNGParseElement(ctxt, nodes);
5277 if (def == NULL) {
5278 def = last = cur;
5279 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00005280 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5281 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005282 def = xmlRelaxNGNewDefine(ctxt, nodes);
5283 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005284 def->content = last;
5285 }
5286 last->next = cur;
5287 last = cur;
5288 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005289 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005290 } else {
5291 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00005292 if (cur != NULL) {
5293 if (def == NULL) {
5294 def = last = cur;
5295 } else {
5296 last->next = cur;
5297 last = cur;
5298 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005299 }
5300 }
5301 nodes = nodes->next;
5302 }
5303 return(def);
5304}
5305
5306/**
5307 * xmlRelaxNGParseStart:
5308 * @ctxt: a Relax-NG parser context
5309 * @nodes: start children nodes
5310 *
5311 * parse the content of a RelaxNG start node.
5312 *
5313 * Returns 0 in case of success, -1 in case of error
5314 */
5315static int
5316xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5317 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005318 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005319
Daniel Veillardd2298792003-02-14 16:54:11 +00005320 if (nodes == NULL) {
5321 if (ctxt->error != NULL)
5322 ctxt->error(ctxt->userData,
5323 "start has no children\n");
5324 ctxt->nbErrors++;
5325 return(-1);
5326 }
5327 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005328 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005329 if (def == NULL)
5330 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005331 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00005332 if (nodes->children != NULL) {
5333 if (ctxt->error != NULL)
5334 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005335 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005336 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005337 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005338 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005339 if (def == NULL)
5340 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005341 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00005342 if (nodes->children != NULL) {
5343 if (ctxt->error != NULL)
5344 ctxt->error(ctxt->userData,
5345 "element notAllowed is not empty\n");
5346 ctxt->nbErrors++;
5347 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005348 } else {
5349 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005350 }
5351 if (ctxt->grammar->start != NULL) {
5352 last = ctxt->grammar->start;
5353 while (last->next != NULL)
5354 last = last->next;
5355 last->next = def;
5356 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005357 ctxt->grammar->start = def;
5358 }
5359 nodes = nodes->next;
5360 if (nodes != NULL) {
5361 if (ctxt->error != NULL)
5362 ctxt->error(ctxt->userData,
5363 "start more than one children\n");
5364 ctxt->nbErrors++;
5365 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005366 }
5367 return(ret);
5368}
5369
5370/**
5371 * xmlRelaxNGParseGrammarContent:
5372 * @ctxt: a Relax-NG parser context
5373 * @nodes: grammar children nodes
5374 *
5375 * parse the content of a RelaxNG grammar node.
5376 *
5377 * Returns 0 in case of success, -1 in case of error
5378 */
5379static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005380xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005381{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005382 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005383
5384 if (nodes == NULL) {
5385 if (ctxt->error != NULL)
5386 ctxt->error(ctxt->userData,
5387 "grammar has no children\n");
5388 ctxt->nbErrors++;
5389 return(-1);
5390 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005391 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005392 if (IS_RELAXNG(nodes, "start")) {
5393 if (nodes->children == NULL) {
5394 if (ctxt->error != NULL)
5395 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00005396 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005397 ctxt->nbErrors++;
5398 } else {
5399 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5400 if (tmp != 0)
5401 ret = -1;
5402 }
5403 } else if (IS_RELAXNG(nodes, "define")) {
5404 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5405 if (tmp != 0)
5406 ret = -1;
5407 } else if (IS_RELAXNG(nodes, "include")) {
5408 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5409 if (tmp != 0)
5410 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005411 } else {
5412 if (ctxt->error != NULL)
5413 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005414 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005415 ctxt->nbErrors++;
5416 ret = -1;
5417 }
5418 nodes = nodes->next;
5419 }
5420 return (ret);
5421}
5422
5423/**
5424 * xmlRelaxNGCheckReference:
5425 * @ref: the ref
5426 * @ctxt: a Relax-NG parser context
5427 * @name: the name associated to the defines
5428 *
5429 * Applies the 4.17. combine attribute rule for all the define
5430 * element of a given grammar using the same name.
5431 */
5432static void
5433xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5434 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5435 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005436 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005437
5438 grammar = ctxt->grammar;
5439 if (grammar == NULL) {
5440 if (ctxt->error != NULL)
5441 ctxt->error(ctxt->userData,
5442 "Internal error: no grammar in CheckReference %s\n",
5443 name);
5444 ctxt->nbErrors++;
5445 return;
5446 }
5447 if (ref->content != NULL) {
5448 if (ctxt->error != NULL)
5449 ctxt->error(ctxt->userData,
5450 "Internal error: reference has content in CheckReference %s\n",
5451 name);
5452 ctxt->nbErrors++;
5453 return;
5454 }
5455 if (grammar->defs != NULL) {
5456 def = xmlHashLookup(grammar->defs, name);
5457 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005458 cur = ref;
5459 while (cur != NULL) {
5460 cur->content = def;
5461 cur = cur->nextHash;
5462 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005463 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005464 if (ctxt->error != NULL)
5465 ctxt->error(ctxt->userData,
5466 "Reference %s has no matching definition\n",
5467 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005468 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005469 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005470 } else {
5471 if (ctxt->error != NULL)
5472 ctxt->error(ctxt->userData,
5473 "Reference %s has no matching definition\n",
5474 name);
5475 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005476 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005477}
5478
5479/**
5480 * xmlRelaxNGCheckCombine:
5481 * @define: the define(s) list
5482 * @ctxt: a Relax-NG parser context
5483 * @name: the name associated to the defines
5484 *
5485 * Applies the 4.17. combine attribute rule for all the define
5486 * element of a given grammar using the same name.
5487 */
5488static void
5489xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5490 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5491 xmlChar *combine;
5492 int choiceOrInterleave = -1;
5493 int missing = 0;
5494 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5495
5496 if (define->nextHash == NULL)
5497 return;
5498 cur = define;
5499 while (cur != NULL) {
5500 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5501 if (combine != NULL) {
5502 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5503 if (choiceOrInterleave == -1)
5504 choiceOrInterleave = 1;
5505 else if (choiceOrInterleave == 0) {
5506 if (ctxt->error != NULL)
5507 ctxt->error(ctxt->userData,
5508 "Defines for %s use both 'choice' and 'interleave'\n",
5509 name);
5510 ctxt->nbErrors++;
5511 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005512 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005513 if (choiceOrInterleave == -1)
5514 choiceOrInterleave = 0;
5515 else if (choiceOrInterleave == 1) {
5516 if (ctxt->error != NULL)
5517 ctxt->error(ctxt->userData,
5518 "Defines for %s use both 'choice' and 'interleave'\n",
5519 name);
5520 ctxt->nbErrors++;
5521 }
5522 } else {
5523 if (ctxt->error != NULL)
5524 ctxt->error(ctxt->userData,
5525 "Defines for %s use unknown combine value '%s''\n",
5526 name, combine);
5527 ctxt->nbErrors++;
5528 }
5529 xmlFree(combine);
5530 } else {
5531 if (missing == 0)
5532 missing = 1;
5533 else {
5534 if (ctxt->error != NULL)
5535 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005536 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005537 name);
5538 ctxt->nbErrors++;
5539 }
5540 }
5541
5542 cur = cur->nextHash;
5543 }
5544#ifdef DEBUG
5545 xmlGenericError(xmlGenericErrorContext,
5546 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5547 name, choiceOrInterleave);
5548#endif
5549 if (choiceOrInterleave == -1)
5550 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005551 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005552 if (cur == NULL)
5553 return;
5554 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005555 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005556 else
5557 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005558 tmp = define;
5559 last = NULL;
5560 while (tmp != NULL) {
5561 if (tmp->content != NULL) {
5562 if (tmp->content->next != NULL) {
5563 /*
5564 * we need first to create a wrapper.
5565 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005566 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005567 if (tmp2 == NULL)
5568 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005569 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005570 tmp2->content = tmp->content;
5571 } else {
5572 tmp2 = tmp->content;
5573 }
5574 if (last == NULL) {
5575 cur->content = tmp2;
5576 } else {
5577 last->next = tmp2;
5578 }
5579 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005580 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005581 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005582 tmp = tmp->nextHash;
5583 }
5584 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005585 if (choiceOrInterleave == 0) {
5586 if (ctxt->interleaves == NULL)
5587 ctxt->interleaves = xmlHashCreate(10);
5588 if (ctxt->interleaves == NULL) {
5589 if (ctxt->error != NULL)
5590 ctxt->error(ctxt->userData,
5591 "Failed to create interleaves hash table\n");
5592 ctxt->nbErrors++;
5593 } else {
5594 char tmpname[32];
5595
5596 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5597 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5598 if (ctxt->error != NULL)
5599 ctxt->error(ctxt->userData,
5600 "Failed to add %s to hash table\n", tmpname);
5601 ctxt->nbErrors++;
5602 }
5603 }
5604 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005605}
5606
5607/**
5608 * xmlRelaxNGCombineStart:
5609 * @ctxt: a Relax-NG parser context
5610 * @grammar: the grammar
5611 *
5612 * Applies the 4.17. combine rule for all the start
5613 * element of a given grammar.
5614 */
5615static void
5616xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5617 xmlRelaxNGGrammarPtr grammar) {
5618 xmlRelaxNGDefinePtr starts;
5619 xmlChar *combine;
5620 int choiceOrInterleave = -1;
5621 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005622 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005623
Daniel Veillard2df2de22003-02-17 23:34:33 +00005624 starts = grammar->start;
5625 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005626 return;
5627 cur = starts;
5628 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005629 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5630 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5631 combine = NULL;
5632 if (ctxt->error != NULL)
5633 ctxt->error(ctxt->userData,
5634 "Internal error: start element not found\n");
5635 ctxt->nbErrors++;
5636 } else {
5637 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5638 }
5639
Daniel Veillard6eadf632003-01-23 18:29:16 +00005640 if (combine != NULL) {
5641 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5642 if (choiceOrInterleave == -1)
5643 choiceOrInterleave = 1;
5644 else if (choiceOrInterleave == 0) {
5645 if (ctxt->error != NULL)
5646 ctxt->error(ctxt->userData,
5647 "<start> use both 'choice' and 'interleave'\n");
5648 ctxt->nbErrors++;
5649 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005650 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005651 if (choiceOrInterleave == -1)
5652 choiceOrInterleave = 0;
5653 else if (choiceOrInterleave == 1) {
5654 if (ctxt->error != NULL)
5655 ctxt->error(ctxt->userData,
5656 "<start> use both 'choice' and 'interleave'\n");
5657 ctxt->nbErrors++;
5658 }
5659 } else {
5660 if (ctxt->error != NULL)
5661 ctxt->error(ctxt->userData,
5662 "<start> uses unknown combine value '%s''\n", combine);
5663 ctxt->nbErrors++;
5664 }
5665 xmlFree(combine);
5666 } else {
5667 if (missing == 0)
5668 missing = 1;
5669 else {
5670 if (ctxt->error != NULL)
5671 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005672 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005673 ctxt->nbErrors++;
5674 }
5675 }
5676
Daniel Veillard2df2de22003-02-17 23:34:33 +00005677 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005678 }
5679#ifdef DEBUG
5680 xmlGenericError(xmlGenericErrorContext,
5681 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5682 choiceOrInterleave);
5683#endif
5684 if (choiceOrInterleave == -1)
5685 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005686 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005687 if (cur == NULL)
5688 return;
5689 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005690 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005691 else
5692 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005693 cur->content = grammar->start;
5694 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005695 if (choiceOrInterleave == 0) {
5696 if (ctxt->interleaves == NULL)
5697 ctxt->interleaves = xmlHashCreate(10);
5698 if (ctxt->interleaves == NULL) {
5699 if (ctxt->error != NULL)
5700 ctxt->error(ctxt->userData,
5701 "Failed to create interleaves hash table\n");
5702 ctxt->nbErrors++;
5703 } else {
5704 char tmpname[32];
5705
5706 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5707 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5708 if (ctxt->error != NULL)
5709 ctxt->error(ctxt->userData,
5710 "Failed to add %s to hash table\n", tmpname);
5711 ctxt->nbErrors++;
5712 }
5713 }
5714 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005715}
5716
5717/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005718 * xmlRelaxNGCheckCycles:
5719 * @ctxt: a Relax-NG parser context
5720 * @nodes: grammar children nodes
5721 * @depth: the counter
5722 *
5723 * Check for cycles.
5724 *
5725 * Returns 0 if check passed, and -1 in case of error
5726 */
5727static int
5728xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5729 xmlRelaxNGDefinePtr cur, int depth) {
5730 int ret = 0;
5731
5732 while ((ret == 0) && (cur != NULL)) {
5733 if ((cur->type == XML_RELAXNG_REF) ||
5734 (cur->type == XML_RELAXNG_PARENTREF)) {
5735 if (cur->depth == -1) {
5736 cur->depth = depth;
5737 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5738 cur->depth = -2;
5739 } else if (depth == cur->depth) {
5740 if (ctxt->error != NULL)
5741 ctxt->error(ctxt->userData,
5742 "Detected a cycle in %s references\n", cur->name);
5743 ctxt->nbErrors++;
5744 return(-1);
5745 }
5746 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5747 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5748 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005749 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005750 }
5751 cur = cur->next;
5752 }
5753 return(ret);
5754}
5755
5756/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005757 * xmlRelaxNGTryUnlink:
5758 * @ctxt: a Relax-NG parser context
5759 * @cur: the definition to unlink
5760 * @parent: the parent definition
5761 * @prev: the previous sibling definition
5762 *
5763 * Try to unlink a definition. If not possble make it a NOOP
5764 *
5765 * Returns the new prev definition
5766 */
5767static xmlRelaxNGDefinePtr
5768xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5769 xmlRelaxNGDefinePtr cur,
5770 xmlRelaxNGDefinePtr parent,
5771 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005772 if (prev != NULL) {
5773 prev->next = cur->next;
5774 } else {
5775 if (parent != NULL) {
5776 if (parent->content == cur)
5777 parent->content = cur->next;
5778 else if (parent->attrs == cur)
5779 parent->attrs = cur->next;
5780 else if (parent->nameClass == cur)
5781 parent->nameClass = cur->next;
5782 } else {
5783 cur->type = XML_RELAXNG_NOOP;
5784 prev = cur;
5785 }
5786 }
5787 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005788}
5789
5790/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005791 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005792 * @ctxt: a Relax-NG parser context
5793 * @nodes: grammar children nodes
5794 *
5795 * Check for simplification of empty and notAllowed
5796 */
5797static void
5798xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5799 xmlRelaxNGDefinePtr cur,
5800 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005801 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005802
Daniel Veillardfd573f12003-03-16 17:52:32 +00005803 while (cur != NULL) {
5804 if ((cur->type == XML_RELAXNG_REF) ||
5805 (cur->type == XML_RELAXNG_PARENTREF)) {
5806 if (cur->depth != -3) {
5807 cur->depth = -3;
5808 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005809 }
5810 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005811 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005812 if ((parent != NULL) &&
5813 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5814 (parent->type == XML_RELAXNG_LIST) ||
5815 (parent->type == XML_RELAXNG_GROUP) ||
5816 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005817 (parent->type == XML_RELAXNG_ONEORMORE) ||
5818 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005819 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005820 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005821 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005822 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005823 (parent->type == XML_RELAXNG_CHOICE)) {
5824 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5825 } else
5826 prev = cur;
5827 } else if (cur->type == XML_RELAXNG_EMPTY){
5828 cur->parent = parent;
5829 if ((parent != NULL) &&
5830 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5831 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005832 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005833 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005834 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005835 if ((parent != NULL) &&
5836 ((parent->type == XML_RELAXNG_GROUP) ||
5837 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5838 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5839 } else
5840 prev = cur;
5841 } else {
5842 cur->parent = parent;
5843 if (cur->content != NULL)
5844 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005845 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005846 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5847 if (cur->nameClass != NULL)
5848 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5849 /*
Daniel Veillardce192eb2003-04-16 15:58:05 +00005850 * On Elements, try to move attribute only generating rules on
5851 * the attrs rules.
5852 */
5853 if (cur->type == XML_RELAXNG_ELEMENT) {
5854 int attronly;
5855 xmlRelaxNGDefinePtr tmp, pre;
5856
5857 while (cur->content != NULL) {
5858 attronly = xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5859 if (attronly == 1) {
5860 /*
5861 * migrate cur->content to attrs
5862 */
5863 tmp = cur->content;
5864 cur->content = tmp->next;
5865 tmp->next = cur->attrs;
5866 cur->attrs = tmp;
5867 } else {
5868 /*
5869 * cur->content can generate elements or text
5870 */
5871 break;
5872 }
5873 }
5874 pre = cur->content;
5875 while ((pre != NULL) && (pre->next != NULL)) {
5876 tmp = pre->next;
5877 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5878 if (attronly == 1) {
5879 /*
5880 * migrate tmp to attrs
5881 */
5882 pre->next = tmp->next;
5883 tmp->next = cur->attrs;
5884 cur->attrs = tmp;
5885 } else {
5886 pre = tmp;
5887 }
5888 }
5889 }
5890 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00005891 * This may result in a simplification
5892 */
5893 if ((cur->type == XML_RELAXNG_GROUP) ||
5894 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5895 if (cur->content == NULL)
5896 cur->type = XML_RELAXNG_EMPTY;
5897 else if (cur->content->next == NULL) {
5898 if ((parent == NULL) && (prev == NULL)) {
5899 cur->type = XML_RELAXNG_NOOP;
5900 } else if (prev == NULL) {
5901 parent->content = cur->content;
5902 cur->content->next = cur->next;
5903 cur = cur->content;
5904 } else {
5905 cur->content->next = cur->next;
5906 prev->next = cur->content;
5907 cur = cur->content;
5908 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005909 }
5910 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005911 /*
5912 * the current node may have been transformed back
5913 */
5914 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5915 (cur->content != NULL) &&
5916 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5917 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5918 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5919 if ((parent != NULL) &&
5920 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5921 (parent->type == XML_RELAXNG_LIST) ||
5922 (parent->type == XML_RELAXNG_GROUP) ||
5923 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5924 (parent->type == XML_RELAXNG_ONEORMORE) ||
5925 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5926 parent->type = XML_RELAXNG_NOT_ALLOWED;
5927 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005928 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005929 if ((parent != NULL) &&
5930 (parent->type == XML_RELAXNG_CHOICE)) {
5931 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5932 } else
5933 prev = cur;
5934 } else if (cur->type == XML_RELAXNG_EMPTY){
5935 if ((parent != NULL) &&
5936 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5937 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5938 parent->type = XML_RELAXNG_EMPTY;
5939 break;
5940 }
5941 if ((parent != NULL) &&
5942 ((parent->type == XML_RELAXNG_GROUP) ||
5943 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5944 (parent->type == XML_RELAXNG_CHOICE))) {
5945 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5946 } else
5947 prev = cur;
5948 } else {
5949 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005950 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005951 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005952 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005953 }
5954}
5955
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005956/**
5957 * xmlRelaxNGGroupContentType:
5958 * @ct1: the first content type
5959 * @ct2: the second content type
5960 *
5961 * Try to group 2 content types
5962 *
5963 * Returns the content type
5964 */
5965static xmlRelaxNGContentType
5966xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5967 xmlRelaxNGContentType ct2) {
5968 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5969 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5970 return(XML_RELAXNG_CONTENT_ERROR);
5971 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5972 return(ct2);
5973 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5974 return(ct1);
5975 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5976 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5977 return(XML_RELAXNG_CONTENT_COMPLEX);
5978 return(XML_RELAXNG_CONTENT_ERROR);
5979}
5980
5981/**
5982 * xmlRelaxNGMaxContentType:
5983 * @ct1: the first content type
5984 * @ct2: the second content type
5985 *
5986 * Compute the max content-type
5987 *
5988 * Returns the content type
5989 */
5990static xmlRelaxNGContentType
5991xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5992 xmlRelaxNGContentType ct2) {
5993 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5994 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5995 return(XML_RELAXNG_CONTENT_ERROR);
5996 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5997 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5998 return(XML_RELAXNG_CONTENT_SIMPLE);
5999 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6000 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6001 return(XML_RELAXNG_CONTENT_COMPLEX);
6002 return(XML_RELAXNG_CONTENT_EMPTY);
6003}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006004
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006005/**
6006 * xmlRelaxNGCheckRules:
6007 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006008 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006009 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006010 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006011 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006012 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006013 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006014 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006015 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006016static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00006017xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6018 xmlRelaxNGDefinePtr cur, int flags,
6019 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006020 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006021 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006022
Daniel Veillardfd573f12003-03-16 17:52:32 +00006023 while (cur != NULL) {
6024 ret = XML_RELAXNG_CONTENT_EMPTY;
6025 if ((cur->type == XML_RELAXNG_REF) ||
6026 (cur->type == XML_RELAXNG_PARENTREF)) {
6027 if (flags & XML_RELAXNG_IN_LIST) {
6028 if (ctxt->error != NULL)
6029 ctxt->error(ctxt->userData,
6030 "Found forbidden pattern list//ref\n");
6031 ctxt->nbErrors++;
6032 }
6033 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6034 if (ctxt->error != NULL)
6035 ctxt->error(ctxt->userData,
6036 "Found forbidden pattern data/except//ref\n");
6037 ctxt->nbErrors++;
6038 }
6039 if (cur->depth > -4) {
6040 cur->depth = -4;
6041 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6042 flags, cur->type);
6043 cur->depth = ret - 15 ;
6044 } else if (cur->depth == -4) {
6045 ret = XML_RELAXNG_CONTENT_COMPLEX;
6046 } else {
6047 ret = (xmlRelaxNGContentType) cur->depth + 15;
6048 }
6049 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6050 /*
6051 * The 7.3 Attribute derivation rule for groups is plugged there
6052 */
6053 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6054 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6055 if (ctxt->error != NULL)
6056 ctxt->error(ctxt->userData,
6057 "Found forbidden pattern data/except//element(ref)\n");
6058 ctxt->nbErrors++;
6059 }
6060 if (flags & XML_RELAXNG_IN_LIST) {
6061 if (ctxt->error != NULL)
6062 ctxt->error(ctxt->userData,
6063 "Found forbidden pattern list//element(ref)\n");
6064 ctxt->nbErrors++;
6065 }
6066 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6067 if (ctxt->error != NULL)
6068 ctxt->error(ctxt->userData,
6069 "Found forbidden pattern attribute//element(ref)\n");
6070 ctxt->nbErrors++;
6071 }
6072 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6073 if (ctxt->error != NULL)
6074 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00006075 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006076 ctxt->nbErrors++;
6077 }
6078 /*
6079 * reset since in the simple form elements are only child
6080 * of grammar/define
6081 */
6082 nflags = 0;
6083 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6084 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6085 if (ctxt->error != NULL)
6086 ctxt->error(ctxt->userData,
6087 "Element %s attributes have a content type error\n",
6088 cur->name);
6089 ctxt->nbErrors++;
6090 }
6091 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6092 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6093 if (ctxt->error != NULL)
6094 ctxt->error(ctxt->userData,
6095 "Element %s has a content type error\n",
6096 cur->name);
6097 ctxt->nbErrors++;
6098 } else {
6099 ret = XML_RELAXNG_CONTENT_COMPLEX;
6100 }
6101 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6102 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6103 if (ctxt->error != NULL)
6104 ctxt->error(ctxt->userData,
6105 "Found forbidden pattern attribute//attribute\n");
6106 ctxt->nbErrors++;
6107 }
6108 if (flags & XML_RELAXNG_IN_LIST) {
6109 if (ctxt->error != NULL)
6110 ctxt->error(ctxt->userData,
6111 "Found forbidden pattern list//attribute\n");
6112 ctxt->nbErrors++;
6113 }
6114 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6115 if (ctxt->error != NULL)
6116 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006117 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006118 ctxt->nbErrors++;
6119 }
6120 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6121 if (ctxt->error != NULL)
6122 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006123 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006124 ctxt->nbErrors++;
6125 }
6126 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6127 if (ctxt->error != NULL)
6128 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006129 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006130 ctxt->nbErrors++;
6131 }
6132 if (flags & XML_RELAXNG_IN_START) {
6133 if (ctxt->error != NULL)
6134 ctxt->error(ctxt->userData,
6135 "Found forbidden pattern start//attribute\n");
6136 ctxt->nbErrors++;
6137 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006138 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
6139 if (cur->ns == NULL) {
6140 if (ctxt->error != NULL)
6141 ctxt->error(ctxt->userData,
6142 "Found anyName attribute without oneOrMore ancestor\n");
6143 ctxt->nbErrors++;
6144 } else {
6145 if (ctxt->error != NULL)
6146 ctxt->error(ctxt->userData,
6147 "Found nsName attribute without oneOrMore ancestor\n");
6148 ctxt->nbErrors++;
6149 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00006150 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006151 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6152 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6153 ret = XML_RELAXNG_CONTENT_EMPTY;
6154 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6155 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6156 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6157 if (ctxt->error != NULL)
6158 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006159 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006160 ctxt->nbErrors++;
6161 }
6162 if (flags & XML_RELAXNG_IN_START) {
6163 if (ctxt->error != NULL)
6164 ctxt->error(ctxt->userData,
6165 "Found forbidden pattern start//oneOrMore\n");
6166 ctxt->nbErrors++;
6167 }
6168 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6169 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6170 ret = xmlRelaxNGGroupContentType(ret, ret);
6171 } else if (cur->type == XML_RELAXNG_LIST) {
6172 if (flags & XML_RELAXNG_IN_LIST) {
6173 if (ctxt->error != NULL)
6174 ctxt->error(ctxt->userData,
6175 "Found forbidden pattern list//list\n");
6176 ctxt->nbErrors++;
6177 }
6178 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6179 if (ctxt->error != NULL)
6180 ctxt->error(ctxt->userData,
6181 "Found forbidden pattern data/except//list\n");
6182 ctxt->nbErrors++;
6183 }
6184 if (flags & XML_RELAXNG_IN_START) {
6185 if (ctxt->error != NULL)
6186 ctxt->error(ctxt->userData,
6187 "Found forbidden pattern start//list\n");
6188 ctxt->nbErrors++;
6189 }
6190 nflags = flags | XML_RELAXNG_IN_LIST;
6191 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6192 } else if (cur->type == XML_RELAXNG_GROUP) {
6193 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6194 if (ctxt->error != NULL)
6195 ctxt->error(ctxt->userData,
6196 "Found forbidden pattern data/except//group\n");
6197 ctxt->nbErrors++;
6198 }
6199 if (flags & XML_RELAXNG_IN_START) {
6200 if (ctxt->error != NULL)
6201 ctxt->error(ctxt->userData,
6202 "Found forbidden pattern start//group\n");
6203 ctxt->nbErrors++;
6204 }
6205 if (flags & XML_RELAXNG_IN_ONEORMORE)
6206 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6207 else
6208 nflags = flags;
6209 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6210 /*
6211 * The 7.3 Attribute derivation rule for groups is plugged there
6212 */
6213 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6214 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6215 if (flags & XML_RELAXNG_IN_LIST) {
6216 if (ctxt->error != NULL)
6217 ctxt->error(ctxt->userData,
6218 "Found forbidden pattern list//interleave\n");
6219 ctxt->nbErrors++;
6220 }
6221 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6222 if (ctxt->error != NULL)
6223 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006224 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006225 ctxt->nbErrors++;
6226 }
6227 if (flags & XML_RELAXNG_IN_START) {
6228 if (ctxt->error != NULL)
6229 ctxt->error(ctxt->userData,
6230 "Found forbidden pattern start//interleave\n");
6231 ctxt->nbErrors++;
6232 }
6233 if (flags & XML_RELAXNG_IN_ONEORMORE)
6234 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6235 else
6236 nflags = flags;
6237 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6238 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6239 if ((cur->parent != NULL) &&
6240 (cur->parent->type == XML_RELAXNG_DATATYPE))
6241 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6242 else
6243 nflags = flags;
6244 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6245 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6246 if (flags & XML_RELAXNG_IN_START) {
6247 if (ctxt->error != NULL)
6248 ctxt->error(ctxt->userData,
6249 "Found forbidden pattern start//data\n");
6250 ctxt->nbErrors++;
6251 }
6252 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6253 ret = XML_RELAXNG_CONTENT_SIMPLE;
6254 } else if (cur->type == XML_RELAXNG_VALUE) {
6255 if (flags & XML_RELAXNG_IN_START) {
6256 if (ctxt->error != NULL)
6257 ctxt->error(ctxt->userData,
6258 "Found forbidden pattern start//value\n");
6259 ctxt->nbErrors++;
6260 }
6261 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6262 ret = XML_RELAXNG_CONTENT_SIMPLE;
6263 } else if (cur->type == XML_RELAXNG_TEXT) {
6264 if (flags & XML_RELAXNG_IN_LIST) {
6265 if (ctxt->error != NULL)
6266 ctxt->error(ctxt->userData,
6267 "Found forbidden pattern list//text\n");
6268 ctxt->nbErrors++;
6269 }
6270 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6271 if (ctxt->error != NULL)
6272 ctxt->error(ctxt->userData,
6273 "Found forbidden pattern data/except//text\n");
6274 ctxt->nbErrors++;
6275 }
6276 if (flags & XML_RELAXNG_IN_START) {
6277 if (ctxt->error != NULL)
6278 ctxt->error(ctxt->userData,
6279 "Found forbidden pattern start//text\n");
6280 ctxt->nbErrors++;
6281 }
6282 ret = XML_RELAXNG_CONTENT_COMPLEX;
6283 } else if (cur->type == XML_RELAXNG_EMPTY) {
6284 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6285 if (ctxt->error != NULL)
6286 ctxt->error(ctxt->userData,
6287 "Found forbidden pattern data/except//empty\n");
6288 ctxt->nbErrors++;
6289 }
6290 if (flags & XML_RELAXNG_IN_START) {
6291 if (ctxt->error != NULL)
6292 ctxt->error(ctxt->userData,
6293 "Found forbidden pattern start//empty\n");
6294 ctxt->nbErrors++;
6295 }
6296 ret = XML_RELAXNG_CONTENT_EMPTY;
6297 } else if (cur->type == XML_RELAXNG_CHOICE) {
6298 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6299 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6300 } else {
6301 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6302 }
6303 cur = cur->next;
6304 if (ptype == XML_RELAXNG_GROUP) {
6305 val = xmlRelaxNGGroupContentType(val, ret);
6306 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6307 tmp = xmlRelaxNGGroupContentType(val, ret);
6308 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6309 tmp = xmlRelaxNGMaxContentType(val, ret);
6310 } else if (ptype == XML_RELAXNG_CHOICE) {
6311 val = xmlRelaxNGMaxContentType(val, ret);
6312 } else if (ptype == XML_RELAXNG_LIST) {
6313 val = XML_RELAXNG_CONTENT_SIMPLE;
6314 } else if (ptype == XML_RELAXNG_EXCEPT) {
6315 if (ret == XML_RELAXNG_CONTENT_ERROR)
6316 val = XML_RELAXNG_CONTENT_ERROR;
6317 else
6318 val = XML_RELAXNG_CONTENT_SIMPLE;
6319 } else {
6320 val = xmlRelaxNGGroupContentType(val, ret);
6321 }
6322
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006323 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006324 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006325}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006326
6327/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006328 * xmlRelaxNGParseGrammar:
6329 * @ctxt: a Relax-NG parser context
6330 * @nodes: grammar children nodes
6331 *
6332 * parse a Relax-NG <grammar> node
6333 *
6334 * Returns the internal xmlRelaxNGGrammarPtr built or
6335 * NULL in case of error
6336 */
6337static xmlRelaxNGGrammarPtr
6338xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6339 xmlRelaxNGGrammarPtr ret, tmp, old;
6340
Daniel Veillardc482e262003-02-26 14:48:48 +00006341#ifdef DEBUG_GRAMMAR
6342 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6343#endif
6344
Daniel Veillard6eadf632003-01-23 18:29:16 +00006345 ret = xmlRelaxNGNewGrammar(ctxt);
6346 if (ret == NULL)
6347 return(NULL);
6348
6349 /*
6350 * Link the new grammar in the tree
6351 */
6352 ret->parent = ctxt->grammar;
6353 if (ctxt->grammar != NULL) {
6354 tmp = ctxt->grammar->children;
6355 if (tmp == NULL) {
6356 ctxt->grammar->children = ret;
6357 } else {
6358 while (tmp->next != NULL)
6359 tmp = tmp->next;
6360 tmp->next = ret;
6361 }
6362 }
6363
6364 old = ctxt->grammar;
6365 ctxt->grammar = ret;
6366 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6367 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006368 if (ctxt->grammar == NULL) {
6369 if (ctxt->error != NULL)
6370 ctxt->error(ctxt->userData,
6371 "Failed to parse <grammar> content\n");
6372 ctxt->nbErrors++;
6373 } else if (ctxt->grammar->start == NULL) {
6374 if (ctxt->error != NULL)
6375 ctxt->error(ctxt->userData,
6376 "Element <grammar> has no <start>\n");
6377 ctxt->nbErrors++;
6378 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006379
6380 /*
6381 * Apply 4.17 mergingd rules to defines and starts
6382 */
6383 xmlRelaxNGCombineStart(ctxt, ret);
6384 if (ret->defs != NULL) {
6385 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6386 ctxt);
6387 }
6388
6389 /*
6390 * link together defines and refs in this grammar
6391 */
6392 if (ret->refs != NULL) {
6393 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6394 ctxt);
6395 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006396
Daniel Veillard6eadf632003-01-23 18:29:16 +00006397 ctxt->grammar = old;
6398 return(ret);
6399}
6400
6401/**
6402 * xmlRelaxNGParseDocument:
6403 * @ctxt: a Relax-NG parser context
6404 * @node: the root node of the RelaxNG schema
6405 *
6406 * parse a Relax-NG definition resource and build an internal
6407 * xmlRelaxNG struture which can be used to validate instances.
6408 *
6409 * Returns the internal XML RelaxNG structure built or
6410 * NULL in case of error
6411 */
6412static xmlRelaxNGPtr
6413xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6414 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006415 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006416 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006417
6418 if ((ctxt == NULL) || (node == NULL))
6419 return (NULL);
6420
6421 schema = xmlRelaxNGNewRelaxNG(ctxt);
6422 if (schema == NULL)
6423 return(NULL);
6424
Daniel Veillard276be4a2003-01-24 01:03:34 +00006425 olddefine = ctxt->define;
6426 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006427 if (IS_RELAXNG(node, "grammar")) {
6428 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6429 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00006430 xmlRelaxNGGrammarPtr tmp, ret;
6431
6432 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006433 if (schema->topgrammar == NULL) {
6434 return(schema);
6435 }
Daniel Veillardc482e262003-02-26 14:48:48 +00006436 /*
6437 * Link the new grammar in the tree
6438 */
6439 ret->parent = ctxt->grammar;
6440 if (ctxt->grammar != NULL) {
6441 tmp = ctxt->grammar->children;
6442 if (tmp == NULL) {
6443 ctxt->grammar->children = ret;
6444 } else {
6445 while (tmp->next != NULL)
6446 tmp = tmp->next;
6447 tmp->next = ret;
6448 }
6449 }
Daniel Veillarde431a272003-01-29 23:02:33 +00006450 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00006451 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006452 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00006453 if (old != NULL)
6454 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006455 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006456 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006457 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006458 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006459 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006460 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6461 while ((schema->topgrammar->start != NULL) &&
6462 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6463 (schema->topgrammar->start->next != NULL))
6464 schema->topgrammar->start = schema->topgrammar->start->content;
6465 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6466 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006467 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006468 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469
6470#ifdef DEBUG
6471 if (schema == NULL)
6472 xmlGenericError(xmlGenericErrorContext,
6473 "xmlRelaxNGParseDocument() failed\n");
6474#endif
6475
6476 return (schema);
6477}
6478
6479/************************************************************************
6480 * *
6481 * Reading RelaxNGs *
6482 * *
6483 ************************************************************************/
6484
6485/**
6486 * xmlRelaxNGNewParserCtxt:
6487 * @URL: the location of the schema
6488 *
6489 * Create an XML RelaxNGs parse context for that file/resource expected
6490 * to contain an XML RelaxNGs file.
6491 *
6492 * Returns the parser context or NULL in case of error
6493 */
6494xmlRelaxNGParserCtxtPtr
6495xmlRelaxNGNewParserCtxt(const char *URL) {
6496 xmlRelaxNGParserCtxtPtr ret;
6497
6498 if (URL == NULL)
6499 return(NULL);
6500
6501 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6502 if (ret == NULL) {
6503 xmlGenericError(xmlGenericErrorContext,
6504 "Failed to allocate new schama parser context for %s\n", URL);
6505 return (NULL);
6506 }
6507 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6508 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006509 ret->error = xmlGenericError;
6510 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006511 return (ret);
6512}
6513
6514/**
6515 * xmlRelaxNGNewMemParserCtxt:
6516 * @buffer: a pointer to a char array containing the schemas
6517 * @size: the size of the array
6518 *
6519 * Create an XML RelaxNGs parse context for that memory buffer expected
6520 * to contain an XML RelaxNGs file.
6521 *
6522 * Returns the parser context or NULL in case of error
6523 */
6524xmlRelaxNGParserCtxtPtr
6525xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6526 xmlRelaxNGParserCtxtPtr ret;
6527
6528 if ((buffer == NULL) || (size <= 0))
6529 return(NULL);
6530
6531 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6532 if (ret == NULL) {
6533 xmlGenericError(xmlGenericErrorContext,
6534 "Failed to allocate new schama parser context\n");
6535 return (NULL);
6536 }
6537 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6538 ret->buffer = buffer;
6539 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006540 ret->error = xmlGenericError;
6541 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006542 return (ret);
6543}
6544
6545/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006546 * xmlRelaxNGNewDocParserCtxt:
6547 * @doc: a preparsed document tree
6548 *
6549 * Create an XML RelaxNGs parser context for that document.
6550 * Note: since the process of compiling a RelaxNG schemas modifies the
6551 * document, the @doc parameter is duplicated internally.
6552 *
6553 * Returns the parser context or NULL in case of error
6554 */
6555xmlRelaxNGParserCtxtPtr
6556xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) {
6557 xmlRelaxNGParserCtxtPtr ret;
6558 xmlDocPtr copy;
6559
6560 if (doc == NULL)
6561 return(NULL);
6562 copy = xmlCopyDoc(doc, 1);
6563 if (copy == NULL)
6564 return(NULL);
6565
6566 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6567 if (ret == NULL) {
6568 xmlGenericError(xmlGenericErrorContext,
6569 "Failed to allocate new schama parser context\n");
6570 return (NULL);
6571 }
6572 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6573 ret->document = copy;
6574 ret->userData = xmlGenericErrorContext;
6575 return (ret);
6576}
6577
6578/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006579 * xmlRelaxNGFreeParserCtxt:
6580 * @ctxt: the schema parser context
6581 *
6582 * Free the resources associated to the schema parser context
6583 */
6584void
6585xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6586 if (ctxt == NULL)
6587 return;
6588 if (ctxt->URL != NULL)
6589 xmlFree(ctxt->URL);
6590 if (ctxt->doc != NULL)
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00006591 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006592 if (ctxt->interleaves != NULL)
6593 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006594 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006595 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006596 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006597 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006598 if (ctxt->docTab != NULL)
6599 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006600 if (ctxt->incTab != NULL)
6601 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006602 if (ctxt->defTab != NULL) {
6603 int i;
6604
6605 for (i = 0;i < ctxt->defNr;i++)
6606 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6607 xmlFree(ctxt->defTab);
6608 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006609 xmlFree(ctxt);
6610}
6611
Daniel Veillard6eadf632003-01-23 18:29:16 +00006612/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006613 * xmlRelaxNGNormExtSpace:
6614 * @value: a value
6615 *
6616 * Removes the leading and ending spaces of the value
6617 * The string is modified "in situ"
6618 */
6619static void
6620xmlRelaxNGNormExtSpace(xmlChar *value) {
6621 xmlChar *start = value;
6622 xmlChar *cur = value;
6623 if (value == NULL)
6624 return;
6625
6626 while (IS_BLANK(*cur)) cur++;
6627 if (cur == start) {
6628 do {
6629 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6630 if (*cur == 0)
6631 return;
6632 start = cur;
6633 while (IS_BLANK(*cur)) cur++;
6634 if (*cur == 0) {
6635 *start = 0;
6636 return;
6637 }
6638 } while (1);
6639 } else {
6640 do {
6641 while ((*cur != 0) && (!IS_BLANK(*cur)))
6642 *start++ = *cur++;
6643 if (*cur == 0) {
6644 *start = 0;
6645 return;
6646 }
6647 /* don't try to normalize the inner spaces */
6648 while (IS_BLANK(*cur)) cur++;
6649 *start++ = *cur++;
6650 if (*cur == 0) {
6651 *start = 0;
6652 return;
6653 }
6654 } while (1);
6655 }
6656}
6657
6658/**
6659 * xmlRelaxNGCheckAttributes:
6660 * @ctxt: a Relax-NG parser context
6661 * @node: a Relax-NG node
6662 *
6663 * Check all the attributes on the given node
6664 */
6665static void
6666xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6667 xmlAttrPtr cur, next;
6668
6669 cur = node->properties;
6670 while (cur != NULL) {
6671 next = cur->next;
6672 if ((cur->ns == NULL) ||
6673 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6674 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6675 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6676 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6677 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6678 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006679 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006680 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6681 if (ctxt->error != NULL)
6682 ctxt->error(ctxt->userData,
6683 "Attribute %s is not allowed on %s\n",
6684 cur->name, node->name);
6685 ctxt->nbErrors++;
6686 }
6687 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6688 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6689 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6690 if (ctxt->error != NULL)
6691 ctxt->error(ctxt->userData,
6692 "Attribute %s is not allowed on %s\n",
6693 cur->name, node->name);
6694 ctxt->nbErrors++;
6695 }
6696 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6697 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6698 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6699 if (ctxt->error != NULL)
6700 ctxt->error(ctxt->userData,
6701 "Attribute %s is not allowed on %s\n",
6702 cur->name, node->name);
6703 ctxt->nbErrors++;
6704 }
6705 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6706 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6707 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6708 if (ctxt->error != NULL)
6709 ctxt->error(ctxt->userData,
6710 "Attribute %s is not allowed on %s\n",
6711 cur->name, node->name);
6712 ctxt->nbErrors++;
6713 }
6714 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6715 xmlChar *val;
6716 xmlURIPtr uri;
6717
6718 val = xmlNodeListGetString(node->doc, cur->children, 1);
6719 if (val != NULL) {
6720 if (val[0] != 0) {
6721 uri = xmlParseURI((const char *) val);
6722 if (uri == NULL) {
6723 if (ctxt->error != NULL)
6724 ctxt->error(ctxt->userData,
6725 "Attribute %s contains invalid URI %s\n",
6726 cur->name, val);
6727 ctxt->nbErrors++;
6728 } else {
6729 if (uri->scheme == NULL) {
6730 if (ctxt->error != NULL)
6731 ctxt->error(ctxt->userData,
6732 "Attribute %s URI %s is not absolute\n",
6733 cur->name, val);
6734 ctxt->nbErrors++;
6735 }
6736 if (uri->fragment != NULL) {
6737 if (ctxt->error != NULL)
6738 ctxt->error(ctxt->userData,
6739 "Attribute %s URI %s has a fragment ID\n",
6740 cur->name, val);
6741 ctxt->nbErrors++;
6742 }
6743 xmlFreeURI(uri);
6744 }
6745 }
6746 xmlFree(val);
6747 }
6748 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6749 if (ctxt->error != NULL)
6750 ctxt->error(ctxt->userData,
6751 "Unknown attribute %s on %s\n",
6752 cur->name, node->name);
6753 ctxt->nbErrors++;
6754 }
6755 }
6756 cur = next;
6757 }
6758}
6759
6760/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006761 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006762 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006763 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006764 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006765 * Cleanup the subtree from unwanted nodes for parsing, resolve
6766 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006767 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006768static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006769xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006770 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006771
Daniel Veillard6eadf632003-01-23 18:29:16 +00006772 delete = NULL;
6773 cur = root;
6774 while (cur != NULL) {
6775 if (delete != NULL) {
6776 xmlUnlinkNode(delete);
6777 xmlFreeNode(delete);
6778 delete = NULL;
6779 }
6780 if (cur->type == XML_ELEMENT_NODE) {
6781 /*
6782 * Simplification 4.1. Annotations
6783 */
6784 if ((cur->ns == NULL) ||
6785 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006786 if ((cur->parent != NULL) &&
6787 (cur->parent->type == XML_ELEMENT_NODE) &&
6788 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6789 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6790 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6791 if (ctxt->error != NULL)
6792 ctxt->error(ctxt->userData,
6793 "element %s doesn't allow foreign elements\n",
6794 cur->parent->name);
6795 ctxt->nbErrors++;
6796 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006797 delete = cur;
6798 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006799 } else {
6800 xmlRelaxNGCleanupAttributes(ctxt, cur);
6801 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6802 xmlChar *href, *ns, *base, *URL;
6803 xmlRelaxNGDocumentPtr docu;
6804 xmlNodePtr tmp;
6805
6806 ns = xmlGetProp(cur, BAD_CAST "ns");
6807 if (ns == NULL) {
6808 tmp = cur->parent;
6809 while ((tmp != NULL) &&
6810 (tmp->type == XML_ELEMENT_NODE)) {
6811 ns = xmlGetProp(tmp, BAD_CAST "ns");
6812 if (ns != NULL)
6813 break;
6814 tmp = tmp->parent;
6815 }
6816 }
6817 href = xmlGetProp(cur, BAD_CAST "href");
6818 if (href == NULL) {
6819 if (ctxt->error != NULL)
6820 ctxt->error(ctxt->userData,
6821 "xmlRelaxNGParse: externalRef has no href attribute\n");
6822 ctxt->nbErrors++;
6823 delete = cur;
6824 goto skip_children;
6825 }
6826 base = xmlNodeGetBase(cur->doc, cur);
6827 URL = xmlBuildURI(href, base);
6828 if (URL == NULL) {
6829 if (ctxt->error != NULL)
6830 ctxt->error(ctxt->userData,
6831 "Failed to compute URL for externalRef %s\n", href);
6832 ctxt->nbErrors++;
6833 if (href != NULL)
6834 xmlFree(href);
6835 if (base != NULL)
6836 xmlFree(base);
6837 delete = cur;
6838 goto skip_children;
6839 }
6840 if (href != NULL)
6841 xmlFree(href);
6842 if (base != NULL)
6843 xmlFree(base);
6844 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6845 if (docu == NULL) {
6846 if (ctxt->error != NULL)
6847 ctxt->error(ctxt->userData,
6848 "Failed to load externalRef %s\n", URL);
6849 ctxt->nbErrors++;
6850 xmlFree(URL);
6851 delete = cur;
6852 goto skip_children;
6853 }
6854 if (ns != NULL)
6855 xmlFree(ns);
6856 xmlFree(URL);
6857 cur->_private = docu;
6858 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6859 xmlChar *href, *ns, *base, *URL;
6860 xmlRelaxNGIncludePtr incl;
6861 xmlNodePtr tmp;
6862
6863 href = xmlGetProp(cur, BAD_CAST "href");
6864 if (href == NULL) {
6865 if (ctxt->error != NULL)
6866 ctxt->error(ctxt->userData,
6867 "xmlRelaxNGParse: include has no href attribute\n");
6868 ctxt->nbErrors++;
6869 delete = cur;
6870 goto skip_children;
6871 }
6872 base = xmlNodeGetBase(cur->doc, cur);
6873 URL = xmlBuildURI(href, base);
6874 if (URL == NULL) {
6875 if (ctxt->error != NULL)
6876 ctxt->error(ctxt->userData,
6877 "Failed to compute URL for include %s\n", href);
6878 ctxt->nbErrors++;
6879 if (href != NULL)
6880 xmlFree(href);
6881 if (base != NULL)
6882 xmlFree(base);
6883 delete = cur;
6884 goto skip_children;
6885 }
6886 if (href != NULL)
6887 xmlFree(href);
6888 if (base != NULL)
6889 xmlFree(base);
6890 ns = xmlGetProp(cur, BAD_CAST "ns");
6891 if (ns == NULL) {
6892 tmp = cur->parent;
6893 while ((tmp != NULL) &&
6894 (tmp->type == XML_ELEMENT_NODE)) {
6895 ns = xmlGetProp(tmp, BAD_CAST "ns");
6896 if (ns != NULL)
6897 break;
6898 tmp = tmp->parent;
6899 }
6900 }
6901 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6902 if (ns != NULL)
6903 xmlFree(ns);
6904 if (incl == NULL) {
6905 if (ctxt->error != NULL)
6906 ctxt->error(ctxt->userData,
6907 "Failed to load include %s\n", URL);
6908 ctxt->nbErrors++;
6909 xmlFree(URL);
6910 delete = cur;
6911 goto skip_children;
6912 }
6913 xmlFree(URL);
6914 cur->_private = incl;
6915 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6916 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6917 xmlChar *name, *ns;
6918 xmlNodePtr text = NULL;
6919
6920 /*
6921 * Simplification 4.8. name attribute of element
6922 * and attribute elements
6923 */
6924 name = xmlGetProp(cur, BAD_CAST "name");
6925 if (name != NULL) {
6926 if (cur->children == NULL) {
6927 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6928 name);
6929 } else {
6930 xmlNodePtr node;
6931 node = xmlNewNode(cur->ns, BAD_CAST "name");
6932 if (node != NULL) {
6933 xmlAddPrevSibling(cur->children, node);
6934 text = xmlNewText(name);
6935 xmlAddChild(node, text);
6936 text = node;
6937 }
6938 }
6939 if (text == NULL) {
6940 if (ctxt->error != NULL)
6941 ctxt->error(ctxt->userData,
6942 "Failed to create a name %s element\n", name);
6943 ctxt->nbErrors++;
6944 }
6945 xmlUnsetProp(cur, BAD_CAST "name");
6946 xmlFree(name);
6947 ns = xmlGetProp(cur, BAD_CAST "ns");
6948 if (ns != NULL) {
6949 if (text != NULL) {
6950 xmlSetProp(text, BAD_CAST "ns", ns);
6951 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6952 }
6953 xmlFree(ns);
6954 } else if (xmlStrEqual(cur->name,
6955 BAD_CAST "attribute")) {
6956 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6957 }
6958 }
6959 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6960 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6961 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6962 /*
6963 * Simplification 4.8. name attribute of element
6964 * and attribute elements
6965 */
6966 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6967 xmlNodePtr node;
6968 xmlChar *ns = NULL;
6969
6970 node = cur->parent;
6971 while ((node != NULL) &&
6972 (node->type == XML_ELEMENT_NODE)) {
6973 ns = xmlGetProp(node, BAD_CAST "ns");
6974 if (ns != NULL) {
6975 break;
6976 }
6977 node = node->parent;
6978 }
6979 if (ns == NULL) {
6980 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6981 } else {
6982 xmlSetProp(cur, BAD_CAST "ns", ns);
6983 xmlFree(ns);
6984 }
6985 }
6986 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6987 xmlChar *name, *local, *prefix;
6988
6989 /*
6990 * Simplification: 4.10. QNames
6991 */
6992 name = xmlNodeGetContent(cur);
6993 if (name != NULL) {
6994 local = xmlSplitQName2(name, &prefix);
6995 if (local != NULL) {
6996 xmlNsPtr ns;
6997
6998 ns = xmlSearchNs(cur->doc, cur, prefix);
6999 if (ns == NULL) {
7000 if (ctxt->error != NULL)
7001 ctxt->error(ctxt->userData,
7002 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
7003 ctxt->nbErrors++;
7004 } else {
7005 xmlSetProp(cur, BAD_CAST "ns", ns->href);
7006 xmlNodeSetContent(cur, local);
7007 }
7008 xmlFree(local);
7009 xmlFree(prefix);
7010 }
7011 xmlFree(name);
7012 }
7013 }
7014 /*
7015 * 4.16
7016 */
7017 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7018 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7019 if (ctxt->error != NULL)
7020 ctxt->error(ctxt->userData,
7021 "Found nsName/except//nsName forbidden construct\n");
7022 ctxt->nbErrors++;
7023 }
7024 }
7025 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7026 (cur != root)) {
7027 int oldflags = ctxt->flags;
7028
7029 /*
7030 * 4.16
7031 */
7032 if ((cur->parent != NULL) &&
7033 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
7034 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7035 xmlRelaxNGCleanupTree(ctxt, cur);
7036 ctxt->flags = oldflags;
7037 goto skip_children;
7038 } else if ((cur->parent != NULL) &&
7039 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
7040 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7041 xmlRelaxNGCleanupTree(ctxt, cur);
7042 ctxt->flags = oldflags;
7043 goto skip_children;
7044 }
7045 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7046 /*
7047 * 4.16
7048 */
7049 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7050 if (ctxt->error != NULL)
7051 ctxt->error(ctxt->userData,
7052 "Found anyName/except//anyName forbidden construct\n");
7053 ctxt->nbErrors++;
7054 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7055 if (ctxt->error != NULL)
7056 ctxt->error(ctxt->userData,
7057 "Found nsName/except//anyName forbidden construct\n");
7058 ctxt->nbErrors++;
7059 }
7060 }
7061 /*
7062 * Thisd is not an else since "include" is transformed
7063 * into a div
7064 */
7065 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7066 xmlChar *ns;
7067 xmlNodePtr child, ins, tmp;
7068
7069 /*
7070 * implements rule 4.11
7071 */
7072
7073 ns = xmlGetProp(cur, BAD_CAST "ns");
7074
7075 child = cur->children;
7076 ins = cur;
7077 while (child != NULL) {
7078 if (ns != NULL) {
7079 if (!xmlHasProp(child, BAD_CAST "ns")) {
7080 xmlSetProp(child, BAD_CAST "ns", ns);
7081 }
7082 }
7083 tmp = child->next;
7084 xmlUnlinkNode(child);
7085 ins = xmlAddNextSibling(ins, child);
7086 child = tmp;
7087 }
7088 if (ns != NULL)
7089 xmlFree(ns);
7090 delete = cur;
7091 goto skip_children;
7092 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007093 }
7094 }
7095 /*
7096 * Simplification 4.2 whitespaces
7097 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007098 else if ((cur->type == XML_TEXT_NODE) ||
7099 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007100 if (IS_BLANK_NODE(cur)) {
7101 if (cur->parent->type == XML_ELEMENT_NODE) {
7102 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
7103 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
7104 delete = cur;
7105 } else {
7106 delete = cur;
7107 goto skip_children;
7108 }
7109 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007110 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007111 delete = cur;
7112 goto skip_children;
7113 }
7114
7115 /*
7116 * Skip to next node
7117 */
7118 if (cur->children != NULL) {
7119 if ((cur->children->type != XML_ENTITY_DECL) &&
7120 (cur->children->type != XML_ENTITY_REF_NODE) &&
7121 (cur->children->type != XML_ENTITY_NODE)) {
7122 cur = cur->children;
7123 continue;
7124 }
7125 }
7126skip_children:
7127 if (cur->next != NULL) {
7128 cur = cur->next;
7129 continue;
7130 }
7131
7132 do {
7133 cur = cur->parent;
7134 if (cur == NULL)
7135 break;
7136 if (cur == root) {
7137 cur = NULL;
7138 break;
7139 }
7140 if (cur->next != NULL) {
7141 cur = cur->next;
7142 break;
7143 }
7144 } while (cur != NULL);
7145 }
7146 if (delete != NULL) {
7147 xmlUnlinkNode(delete);
7148 xmlFreeNode(delete);
7149 delete = NULL;
7150 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007151}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007152
Daniel Veillardc5312d72003-02-21 17:14:10 +00007153/**
7154 * xmlRelaxNGCleanupDoc:
7155 * @ctxt: a Relax-NG parser context
7156 * @doc: an xmldocPtr document pointer
7157 *
7158 * Cleanup the document from unwanted nodes for parsing, resolve
7159 * Include and externalRef lookups.
7160 *
7161 * Returns the cleaned up document or NULL in case of error
7162 */
7163static xmlDocPtr
7164xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
7165 xmlNodePtr root;
7166
7167 /*
7168 * Extract the root
7169 */
7170 root = xmlDocGetRootElement(doc);
7171 if (root == NULL) {
7172 if (ctxt->error != NULL)
7173 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7174 ctxt->URL);
7175 ctxt->nbErrors++;
7176 return (NULL);
7177 }
7178 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007179 return(doc);
7180}
7181
7182/**
7183 * xmlRelaxNGParse:
7184 * @ctxt: a Relax-NG parser context
7185 *
7186 * parse a schema definition resource and build an internal
7187 * XML Shema struture which can be used to validate instances.
7188 * *WARNING* this interface is highly subject to change
7189 *
7190 * Returns the internal XML RelaxNG structure built from the resource or
7191 * NULL in case of error
7192 */
7193xmlRelaxNGPtr
7194xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7195{
7196 xmlRelaxNGPtr ret = NULL;
7197 xmlDocPtr doc;
7198 xmlNodePtr root;
7199
7200 xmlRelaxNGInitTypes();
7201
7202 if (ctxt == NULL)
7203 return (NULL);
7204
7205 /*
7206 * First step is to parse the input document into an DOM/Infoset
7207 */
7208 if (ctxt->URL != NULL) {
7209 doc = xmlParseFile((const char *) ctxt->URL);
7210 if (doc == NULL) {
7211 if (ctxt->error != NULL)
7212 ctxt->error(ctxt->userData,
7213 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7214 ctxt->nbErrors++;
7215 return (NULL);
7216 }
7217 } else if (ctxt->buffer != NULL) {
7218 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7219 if (doc == NULL) {
7220 if (ctxt->error != NULL)
7221 ctxt->error(ctxt->userData,
7222 "xmlRelaxNGParse: could not parse schemas\n");
7223 ctxt->nbErrors++;
7224 return (NULL);
7225 }
7226 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7227 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007228 } else if (ctxt->document != NULL) {
7229 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007230 } else {
7231 if (ctxt->error != NULL)
7232 ctxt->error(ctxt->userData,
7233 "xmlRelaxNGParse: nothing to parse\n");
7234 ctxt->nbErrors++;
7235 return (NULL);
7236 }
7237 ctxt->document = doc;
7238
7239 /*
7240 * Some preprocessing of the document content
7241 */
7242 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7243 if (doc == NULL) {
7244 xmlFreeDoc(ctxt->document);
7245 ctxt->document = NULL;
7246 return(NULL);
7247 }
7248
Daniel Veillard6eadf632003-01-23 18:29:16 +00007249 /*
7250 * Then do the parsing for good
7251 */
7252 root = xmlDocGetRootElement(doc);
7253 if (root == NULL) {
7254 if (ctxt->error != NULL)
7255 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7256 ctxt->URL);
7257 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007258 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007259 return (NULL);
7260 }
7261 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007262 if (ret == NULL) {
7263 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007264 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007265 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007266
7267 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007268 * Check the ref/defines links
7269 */
7270 /*
7271 * try to preprocess interleaves
7272 */
7273 if (ctxt->interleaves != NULL) {
7274 xmlHashScan(ctxt->interleaves,
7275 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7276 }
7277
7278 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007279 * if there was a parsing error return NULL
7280 */
7281 if (ctxt->nbErrors > 0) {
7282 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007283 ctxt->document = NULL;
7284 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007285 return(NULL);
7286 }
7287
7288 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007289 * try to compile (parts of) the schemas
7290 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007291 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7292 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00007293 xmlRelaxNGDefinePtr def;
7294
7295 def = xmlRelaxNGNewDefine(ctxt, NULL);
7296 if (def != NULL) {
7297 def->type = XML_RELAXNG_START;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007298 def->content = ret->topgrammar->start;
7299 ret->topgrammar->start = def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007300 }
7301 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007302 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007303 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007304
7305 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007306 * Transfer the pointer for cleanup at the schema level.
7307 */
7308 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007309 ctxt->document = NULL;
7310 ret->documents = ctxt->documents;
7311 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007312
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007313 ret->includes = ctxt->includes;
7314 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007315 ret->defNr = ctxt->defNr;
7316 ret->defTab = ctxt->defTab;
7317 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007318 if (ctxt->idref == 1)
7319 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007320
7321 return (ret);
7322}
7323
7324/**
7325 * xmlRelaxNGSetParserErrors:
7326 * @ctxt: a Relax-NG validation context
7327 * @err: the error callback
7328 * @warn: the warning callback
7329 * @ctx: contextual data for the callbacks
7330 *
7331 * Set the callback functions used to handle errors for a validation context
7332 */
7333void
7334xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7335 xmlRelaxNGValidityErrorFunc err,
7336 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7337 if (ctxt == NULL)
7338 return;
7339 ctxt->error = err;
7340 ctxt->warning = warn;
7341 ctxt->userData = ctx;
7342}
Daniel Veillard409a8142003-07-18 15:16:57 +00007343
7344/**
7345 * xmlRelaxNGGetParserErrors:
7346 * @ctxt: a Relax-NG validation context
7347 * @err: the error callback result
7348 * @warn: the warning callback result
7349 * @ctx: contextual data for the callbacks result
7350 *
7351 * Get the callback information used to handle errors for a validation context
7352 *
7353 * Returns -1 in case of failure, 0 otherwise.
7354 */
7355int
7356xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7357 xmlRelaxNGValidityErrorFunc *err,
7358 xmlRelaxNGValidityWarningFunc *warn, void **ctx) {
7359 if (ctxt == NULL)
7360 return(-1);
7361 if (err != NULL) *err = ctxt->error;
7362 if (warn != NULL) *warn = ctxt->warning;
7363 if (ctx != NULL) *ctx = ctxt->userData;
7364 return(0);
7365}
7366
Daniel Veillard6eadf632003-01-23 18:29:16 +00007367/************************************************************************
7368 * *
7369 * Dump back a compiled form *
7370 * *
7371 ************************************************************************/
7372static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7373
7374/**
7375 * xmlRelaxNGDumpDefines:
7376 * @output: the file output
7377 * @defines: a list of define structures
7378 *
7379 * Dump a RelaxNG structure back
7380 */
7381static void
7382xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7383 while (defines != NULL) {
7384 xmlRelaxNGDumpDefine(output, defines);
7385 defines = defines->next;
7386 }
7387}
7388
7389/**
7390 * xmlRelaxNGDumpDefine:
7391 * @output: the file output
7392 * @define: a define structure
7393 *
7394 * Dump a RelaxNG structure back
7395 */
7396static void
7397xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7398 if (define == NULL)
7399 return;
7400 switch(define->type) {
7401 case XML_RELAXNG_EMPTY:
7402 fprintf(output, "<empty/>\n");
7403 break;
7404 case XML_RELAXNG_NOT_ALLOWED:
7405 fprintf(output, "<notAllowed/>\n");
7406 break;
7407 case XML_RELAXNG_TEXT:
7408 fprintf(output, "<text/>\n");
7409 break;
7410 case XML_RELAXNG_ELEMENT:
7411 fprintf(output, "<element>\n");
7412 if (define->name != NULL) {
7413 fprintf(output, "<name");
7414 if (define->ns != NULL)
7415 fprintf(output, " ns=\"%s\"", define->ns);
7416 fprintf(output, ">%s</name>\n", define->name);
7417 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007418 xmlRelaxNGDumpDefines(output, define->attrs);
7419 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007420 fprintf(output, "</element>\n");
7421 break;
7422 case XML_RELAXNG_LIST:
7423 fprintf(output, "<list>\n");
7424 xmlRelaxNGDumpDefines(output, define->content);
7425 fprintf(output, "</list>\n");
7426 break;
7427 case XML_RELAXNG_ONEORMORE:
7428 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007429 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007430 fprintf(output, "</oneOrMore>\n");
7431 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007432 case XML_RELAXNG_ZEROORMORE:
7433 fprintf(output, "<zeroOrMore>\n");
7434 xmlRelaxNGDumpDefines(output, define->content);
7435 fprintf(output, "</zeroOrMore>\n");
7436 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007437 case XML_RELAXNG_CHOICE:
7438 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007439 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007440 fprintf(output, "</choice>\n");
7441 break;
7442 case XML_RELAXNG_GROUP:
7443 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007444 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007445 fprintf(output, "</group>\n");
7446 break;
7447 case XML_RELAXNG_INTERLEAVE:
7448 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007449 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007450 fprintf(output, "</interleave>\n");
7451 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007452 case XML_RELAXNG_OPTIONAL:
7453 fprintf(output, "<optional>\n");
7454 xmlRelaxNGDumpDefines(output, define->content);
7455 fprintf(output, "</optional>\n");
7456 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007457 case XML_RELAXNG_ATTRIBUTE:
7458 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007459 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007460 fprintf(output, "</attribute>\n");
7461 break;
7462 case XML_RELAXNG_DEF:
7463 fprintf(output, "<define");
7464 if (define->name != NULL)
7465 fprintf(output, " name=\"%s\"", define->name);
7466 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007467 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007468 fprintf(output, "</define>\n");
7469 break;
7470 case XML_RELAXNG_REF:
7471 fprintf(output, "<ref");
7472 if (define->name != NULL)
7473 fprintf(output, " name=\"%s\"", define->name);
7474 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007475 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007476 fprintf(output, "</ref>\n");
7477 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007478 case XML_RELAXNG_PARENTREF:
7479 fprintf(output, "<parentRef");
7480 if (define->name != NULL)
7481 fprintf(output, " name=\"%s\"", define->name);
7482 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007483 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00007484 fprintf(output, "</parentRef>\n");
7485 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007486 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00007487 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007488 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00007489 fprintf(output, "</externalRef>\n");
7490 break;
7491 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007492 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007493 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00007494 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007495 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007496 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007497 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007498 TODO
7499 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007500 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007501 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00007502 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007503 }
7504}
7505
7506/**
7507 * xmlRelaxNGDumpGrammar:
7508 * @output: the file output
7509 * @grammar: a grammar structure
7510 * @top: is this a top grammar
7511 *
7512 * Dump a RelaxNG structure back
7513 */
7514static void
7515xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7516{
7517 if (grammar == NULL)
7518 return;
7519
7520 fprintf(output, "<grammar");
7521 if (top)
7522 fprintf(output,
7523 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7524 switch(grammar->combine) {
7525 case XML_RELAXNG_COMBINE_UNDEFINED:
7526 break;
7527 case XML_RELAXNG_COMBINE_CHOICE:
7528 fprintf(output, " combine=\"choice\"");
7529 break;
7530 case XML_RELAXNG_COMBINE_INTERLEAVE:
7531 fprintf(output, " combine=\"interleave\"");
7532 break;
7533 default:
7534 fprintf(output, " <!-- invalid combine value -->");
7535 }
7536 fprintf(output, ">\n");
7537 if (grammar->start == NULL) {
7538 fprintf(output, " <!-- grammar had no start -->");
7539 } else {
7540 fprintf(output, "<start>\n");
7541 xmlRelaxNGDumpDefine(output, grammar->start);
7542 fprintf(output, "</start>\n");
7543 }
7544 /* TODO ? Dump the defines ? */
7545 fprintf(output, "</grammar>\n");
7546}
7547
7548/**
7549 * xmlRelaxNGDump:
7550 * @output: the file output
7551 * @schema: a schema structure
7552 *
7553 * Dump a RelaxNG structure back
7554 */
7555void
7556xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7557{
7558 if (schema == NULL) {
7559 fprintf(output, "RelaxNG empty or failed to compile\n");
7560 return;
7561 }
7562 fprintf(output, "RelaxNG: ");
7563 if (schema->doc == NULL) {
7564 fprintf(output, "no document\n");
7565 } else if (schema->doc->URL != NULL) {
7566 fprintf(output, "%s\n", schema->doc->URL);
7567 } else {
7568 fprintf(output, "\n");
7569 }
7570 if (schema->topgrammar == NULL) {
7571 fprintf(output, "RelaxNG has no top grammar\n");
7572 return;
7573 }
7574 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7575}
7576
Daniel Veillardfebcca42003-02-16 15:44:18 +00007577/**
7578 * xmlRelaxNGDumpTree:
7579 * @output: the file output
7580 * @schema: a schema structure
7581 *
7582 * Dump the transformed RelaxNG tree.
7583 */
7584void
7585xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7586{
7587 if (schema == NULL) {
7588 fprintf(output, "RelaxNG empty or failed to compile\n");
7589 return;
7590 }
7591 if (schema->doc == NULL) {
7592 fprintf(output, "no document\n");
7593 } else {
7594 xmlDocDump(output, schema->doc);
7595 }
7596}
7597
Daniel Veillard6eadf632003-01-23 18:29:16 +00007598/************************************************************************
7599 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007600 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007601 * *
7602 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007603static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7604 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007605
7606/**
7607 * xmlRelaxNGValidateCompiledCallback:
7608 * @exec: the regular expression instance
7609 * @token: the token which matched
7610 * @transdata: callback data, the define for the subelement if available
7611 @ @inputdata: callback data, the Relax NG validation context
7612 *
7613 * Handle the callback and if needed validate the element children.
7614 */
7615static void
7616xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7617 const xmlChar *token,
7618 void *transdata,
7619 void *inputdata) {
7620 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7621 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7622 int ret;
7623
7624#ifdef DEBUG_COMPILE
7625 xmlGenericError(xmlGenericErrorContext,
7626 "Compiled callback for: '%s'\n", token);
7627#endif
7628 if (ctxt == NULL) {
7629 fprintf(stderr, "callback on %s missing context\n", token);
7630 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7631 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7632 return;
7633 }
7634 if (define == NULL) {
7635 if (token[0] == '#')
7636 return;
7637 fprintf(stderr, "callback on %s missing define\n", token);
7638 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7639 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7640 return;
7641 }
7642 if ((ctxt == NULL) || (define == NULL)) {
7643 fprintf(stderr, "callback on %s missing info\n", token);
7644 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7645 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7646 return;
7647 } else if (define->type != XML_RELAXNG_ELEMENT) {
7648 fprintf(stderr, "callback on %s define is not element\n", token);
7649 if (ctxt->errNo == XML_RELAXNG_OK)
7650 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7651 return;
7652 }
7653 ret = xmlRelaxNGValidateDefinition(ctxt, define);
7654}
7655
7656/**
7657 * xmlRelaxNGValidateCompiledContent:
7658 * @ctxt: the RelaxNG validation context
7659 * @regexp: the regular expression as compiled
7660 * @content: list of children to test against the regexp
7661 *
7662 * Validate the content model of an element or start using the regexp
7663 *
7664 * Returns 0 in case of success, -1 in case of error.
7665 */
7666static int
7667xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7668 xmlRegexpPtr regexp, xmlNodePtr content) {
7669 xmlRegExecCtxtPtr exec;
7670 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007671 int ret = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007672
7673 if ((ctxt == NULL) || (regexp == NULL))
7674 return(-1);
7675 exec = xmlRegNewExecCtxt(regexp,
7676 xmlRelaxNGValidateCompiledCallback, ctxt);
7677 cur = content;
7678 while (cur != NULL) {
7679 ctxt->state->seq = cur;
7680 switch (cur->type) {
7681 case XML_TEXT_NODE:
7682 case XML_CDATA_SECTION_NODE:
7683 if (xmlIsBlankNode(cur))
7684 break;
7685 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7686 if (ret < 0) {
7687 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7688 }
7689 break;
7690 case XML_ELEMENT_NODE:
7691 if (cur->ns != NULL) {
7692 ret = xmlRegExecPushString2(exec, cur->name,
7693 cur->ns->href, ctxt);
7694 } else {
7695 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7696 }
7697 if (ret < 0) {
7698 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7699 }
7700 break;
7701 default:
7702 break;
7703 }
7704 if (ret < 0) break;
7705 /*
7706 * Switch to next element
7707 */
7708 cur = cur->next;
7709 }
7710 ret = xmlRegExecPushString(exec, NULL, NULL);
7711 if (ret == 1) {
7712 ret = 0;
7713 ctxt->state->seq = NULL;
7714 } else if (ret == 0) {
7715 /*
Daniel Veillardf4e55762003-04-15 23:32:22 +00007716 * TODO: get some of the names needed to exit the current state of exec
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007717 */
7718 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7719 ret = -1;
7720 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7721 xmlRelaxNGDumpValidError(ctxt);
7722 } else {
7723 ret = -1;
7724 }
7725 xmlRegFreeExecCtxt(exec);
7726 return(ret);
7727}
7728
7729/************************************************************************
7730 * *
7731 * Progressive validation of when possible *
7732 * *
7733 ************************************************************************/
Daniel Veillardf4e55762003-04-15 23:32:22 +00007734static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7735 xmlRelaxNGDefinePtr defines);
7736static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt);
7737
7738/**
7739 * xmlRelaxNGElemPush:
7740 * @ctxt: the validation context
7741 * @exec: the regexp runtime for the new content model
7742 *
7743 * Push a new regexp for the current node content model on the stack
7744 *
7745 * Returns 0 in case of success and -1 in case of error.
7746 */
7747static int
7748xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) {
7749 if (ctxt->elemTab == NULL) {
7750 ctxt->elemMax = 10;
7751 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7752 sizeof(xmlRegExecCtxtPtr));
7753 if (ctxt->elemTab == NULL) {
7754 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7755 return(-1);
7756 }
7757 }
7758 if (ctxt->elemNr >= ctxt->elemMax) {
7759 ctxt->elemMax *= 2;
7760 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7761 ctxt->elemMax * sizeof(xmlRegExecCtxtPtr));
7762 if (ctxt->elemTab == NULL) {
7763 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7764 return(-1);
7765 }
7766 }
7767 ctxt->elemTab[ctxt->elemNr++] = exec;
7768 ctxt->elem = exec;
7769 return(0);
7770}
7771
7772/**
7773 * xmlRelaxNGElemPop:
7774 * @ctxt: the validation context
7775 *
7776 * Pop the regexp of the current node content model from the stack
7777 *
7778 * Returns the exec or NULL if empty
7779 */
7780static xmlRegExecCtxtPtr
7781xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) {
7782 xmlRegExecCtxtPtr ret;
7783
7784 if (ctxt->elemNr <= 0) return(NULL);
7785 ctxt->elemNr--;
7786 ret = ctxt->elemTab[ctxt->elemNr];
7787 ctxt->elemTab[ctxt->elemNr] = NULL;
7788 if (ctxt->elemNr > 0)
7789 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7790 else
7791 ctxt->elem = NULL;
7792 return(ret);
7793}
7794
7795/**
7796 * xmlRelaxNGValidateProgressiveCallback:
7797 * @exec: the regular expression instance
7798 * @token: the token which matched
7799 * @transdata: callback data, the define for the subelement if available
7800 @ @inputdata: callback data, the Relax NG validation context
7801 *
7802 * Handle the callback and if needed validate the element children.
7803 * some of the in/out informations are passed via the context in @inputdata.
7804 */
7805static void
7806xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7807 const xmlChar *token,
7808 void *transdata,
7809 void *inputdata) {
7810 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7811 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007812 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007813 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007814 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007815
7816#ifdef DEBUG_PROGRESSIVE
7817 xmlGenericError(xmlGenericErrorContext,
7818 "Progressive callback for: '%s'\n", token);
7819#endif
7820 if (ctxt == NULL) {
7821 fprintf(stderr, "callback on %s missing context\n", token);
7822 return;
7823 }
7824 ctxt->pstate = 1;
7825 if (define == NULL) {
7826 if (token[0] == '#')
7827 return;
7828 fprintf(stderr, "callback on %s missing define\n", token);
7829 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7830 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7831 ctxt->pstate = -1;
7832 return;
7833 }
7834 if ((ctxt == NULL) || (define == NULL)) {
7835 fprintf(stderr, "callback on %s missing info\n", token);
7836 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7837 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7838 ctxt->pstate = -1;
7839 return;
7840 } else if (define->type != XML_RELAXNG_ELEMENT) {
7841 fprintf(stderr, "callback on %s define is not element\n", token);
7842 if (ctxt->errNo == XML_RELAXNG_OK)
7843 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7844 ctxt->pstate = -1;
7845 return;
7846 }
7847 if (node->type != XML_ELEMENT_NODE) {
7848 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7849 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7850 xmlRelaxNGDumpValidError(ctxt);
7851 ctxt->pstate = -1;
7852 return;
7853 }
7854 if (define->contModel == NULL) {
7855 /*
7856 * this node cannot be validated in a streamable fashion
7857 */
7858#ifdef DEBUG_PROGRESSIVE
7859 xmlGenericError(xmlGenericErrorContext,
7860 "Element '%s' validation is not streamable\n", token);
7861#endif
7862 ctxt->pstate = 0;
7863 ctxt->pdef = define;
7864 return;
7865 }
7866 exec = xmlRegNewExecCtxt(define->contModel,
7867 xmlRelaxNGValidateProgressiveCallback,
7868 ctxt);
7869 if (exec == NULL) {
7870 ctxt->pstate = -1;
7871 return;
7872 }
7873 xmlRelaxNGElemPush(ctxt, exec);
7874
7875 /*
7876 * Validate the attributes part of the content.
7877 */
7878 state = xmlRelaxNGNewValidState(ctxt, node);
7879 if (state == NULL) {
7880 ctxt->pstate = -1;
7881 return;
7882 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007883 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007884 ctxt->state = state;
7885 if (define->attrs != NULL) {
7886 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7887 if (ret != 0) {
7888 ctxt->pstate = -1;
7889 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7890 }
7891 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007892 if (ctxt->state != NULL) {
7893 ctxt->state->seq = NULL;
7894 ret = xmlRelaxNGValidateElementEnd(ctxt);
7895 if (ret != 0) {
7896 ctxt->pstate = -1;
7897 }
7898 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
7899 } else if (ctxt->states != NULL) {
7900 int tmp = -1, i;
7901
7902 oldflags = ctxt->flags;
7903 ctxt->flags |= FLAGS_IGNORABLE;
7904
7905 for (i = 0; i < ctxt->states->nbState; i++) {
7906 state = ctxt->states->tabState[i];
7907 ctxt->state = state;
7908 ctxt->state->seq = NULL;
7909
7910 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7911 tmp = 0;
7912 xmlRelaxNGFreeValidState(ctxt, state);
7913 }
7914 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7915 ctxt->states = NULL;
7916 if ((ret == 0) && (tmp == -1))
7917 ctxt->pstate = -1;
7918 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007919 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007920 if (ctxt->pstate == -1) {
7921 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
7922 xmlRelaxNGDumpValidError(ctxt);
7923 }
7924 }
7925 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007926}
7927
7928/**
7929 * xmlRelaxNGValidatePushElement:
7930 * @ctxt: the validation context
7931 * @doc: a document instance
7932 * @elem: an element instance
7933 *
7934 * Push a new element start on the RelaxNG validation stack.
7935 *
7936 * returns 1 if no validation problem was found or 0 if validating the
7937 * element requires a full node, and -1 in case of error.
7938 */
7939int
Daniel Veillard33300b42003-04-17 09:09:19 +00007940xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
7941 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00007942 xmlNodePtr elem)
7943{
7944 int ret = 1;
7945
7946 if ((ctxt == NULL) || (elem == NULL))
7947 return (-1);
7948
7949#ifdef DEBUG_PROGRESSIVE
7950 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
7951#endif
7952 if (ctxt->elem == 0) {
7953 xmlRelaxNGPtr schema;
7954 xmlRelaxNGGrammarPtr grammar;
7955 xmlRegExecCtxtPtr exec;
7956 xmlRelaxNGDefinePtr define;
7957
7958 schema = ctxt->schema;
7959 if (schema == NULL) {
7960 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7961 return (-1);
7962 }
7963 grammar = schema->topgrammar;
7964 if ((grammar == NULL) || (grammar->start == NULL)) {
7965 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7966 return (-1);
7967 }
7968 define = grammar->start;
7969 if (define->contModel == NULL) {
7970 ctxt->pdef = define;
7971 return (0);
7972 }
7973 exec = xmlRegNewExecCtxt(define->contModel,
7974 xmlRelaxNGValidateProgressiveCallback,
7975 ctxt);
7976 if (exec == NULL) {
7977 return (-1);
7978 }
7979 xmlRelaxNGElemPush(ctxt, exec);
7980 }
7981 ctxt->pnode = elem;
7982 ctxt->pstate = 0;
7983 if (elem->ns != NULL) {
7984 ret =
7985 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
7986 ctxt);
7987 } else {
7988 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
7989 }
7990 if (ret < 0) {
7991 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
7992 } else {
7993 if (ctxt->pstate == 0)
7994 ret = 0;
7995 else if (ctxt->pstate < 0)
7996 ret = -1;
7997 else
7998 ret = 1;
7999 }
8000#ifdef DEBUG_PROGRESSIVE
8001 if (ret < 0)
8002 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8003 elem->name);
8004#endif
8005 return (ret);
8006}
8007
8008/**
8009 * xmlRelaxNGValidatePushCData:
8010 * @ctxt: the RelaxNG validation context
8011 * @data: some character data read
8012 * @len: the lenght of the data
8013 *
8014 * check the CData parsed for validation in the current stack
8015 *
8016 * returns 1 if no validation problem was found or -1 otherwise
8017 */
8018int
8019xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard33300b42003-04-17 09:09:19 +00008020 const xmlChar * data,
8021 int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008022{
8023 int ret = 1;
8024
8025 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8026 return (-1);
8027
8028#ifdef DEBUG_PROGRESSIVE
8029 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8030#endif
8031
8032 while (*data != 0) {
8033 if (!IS_BLANK(*data))
8034 break;
8035 data++;
8036 }
8037 if (*data == 0)
8038 return(1);
8039
8040 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8041 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008042 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008043#ifdef DEBUG_PROGRESSIVE
8044 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
8045#endif
8046
8047 return(-1);
8048 }
8049 return(1);
8050}
8051
8052/**
8053 * xmlRelaxNGValidatePopElement:
8054 * @ctxt: the RelaxNG validation context
8055 * @doc: a document instance
8056 * @elem: an element instance
8057 *
8058 * Pop the element end from the RelaxNG validation stack.
8059 *
8060 * returns 1 if no validation problem was found or 0 otherwise
8061 */
8062int
8063xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8064 xmlDocPtr doc ATTRIBUTE_UNUSED,
8065 xmlNodePtr elem) {
8066 int ret;
8067 xmlRegExecCtxtPtr exec;
8068
8069 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) return(-1);
8070#ifdef DEBUG_PROGRESSIVE
8071 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8072#endif
8073 /*
8074 * verify that we reached a terminal state of the content model.
8075 */
8076 exec = xmlRelaxNGElemPop(ctxt);
8077 ret = xmlRegExecPushString(exec, NULL, NULL);
8078 if (ret == 0) {
8079 /*
8080 * TODO: get some of the names needed to exit the current state of exec
8081 */
8082 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8083 ret = -1;
8084 } else if (ret < 0) {
8085 ret = -1;
8086 } else {
8087 ret = 1;
8088 }
8089 xmlRegFreeExecCtxt(exec);
8090#ifdef DEBUG_PROGRESSIVE
8091 if (ret < 0)
8092 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8093 elem->name);
8094#endif
8095 return(ret);
8096}
8097
8098/**
8099 * xmlRelaxNGValidateFullElement:
8100 * @ctxt: the validation context
8101 * @doc: a document instance
8102 * @elem: an element instance
8103 *
8104 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8105 * 0 and the content of the node has been expanded.
8106 *
8107 * returns 1 if no validation problem was found or -1 in case of error.
8108 */
8109int
Daniel Veillard33300b42003-04-17 09:09:19 +00008110xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8111 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008112 xmlNodePtr elem) {
8113 int ret;
8114 xmlRelaxNGValidStatePtr state;
8115
8116 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) return(-1);
8117#ifdef DEBUG_PROGRESSIVE
8118 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8119#endif
8120 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8121 if (state == NULL) {
8122 return(-1);
8123 }
8124 state->seq = elem;
8125 ctxt->state = state;
8126 ctxt->errNo = XML_RELAXNG_OK;
8127 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8128 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) ret = -1;
8129 else ret = 1;
8130 xmlRelaxNGFreeValidState(ctxt, state);
8131 ctxt->state = NULL;
8132#ifdef DEBUG_PROGRESSIVE
8133 if (ret < 0)
8134 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8135 elem->name);
8136#endif
8137 return(ret);
8138}
8139
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008140/************************************************************************
8141 * *
8142 * Generic interpreted validation implementation *
8143 * *
8144 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008145static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8146 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008147
8148/**
8149 * xmlRelaxNGSkipIgnored:
8150 * @ctxt: a schema validation context
8151 * @node: the top node.
8152 *
8153 * Skip ignorable nodes in that context
8154 *
8155 * Returns the new sibling or NULL in case of error.
8156 */
8157static xmlNodePtr
8158xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8159 xmlNodePtr node) {
8160 /*
8161 * TODO complete and handle entities
8162 */
8163 while ((node != NULL) &&
8164 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008165 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008166 (((node->type == XML_TEXT_NODE) ||
8167 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008168 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8169 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00008170 node = node->next;
8171 }
8172 return(node);
8173}
8174
8175/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008176 * xmlRelaxNGNormalize:
8177 * @ctxt: a schema validation context
8178 * @str: the string to normalize
8179 *
8180 * Implements the normalizeWhiteSpace( s ) function from
8181 * section 6.2.9 of the spec
8182 *
8183 * Returns the new string or NULL in case of error.
8184 */
8185static xmlChar *
8186xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
8187 xmlChar *ret, *p;
8188 const xmlChar *tmp;
8189 int len;
8190
8191 if (str == NULL)
8192 return(NULL);
8193 tmp = str;
8194 while (*tmp != 0) tmp++;
8195 len = tmp - str;
8196
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008197 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008198 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008199 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008200 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008201 } else {
8202 xmlGenericError(xmlGenericErrorContext,
8203 "xmlRelaxNGNormalize: out of memory\n");
8204 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008205 return(NULL);
8206 }
8207 p = ret;
8208 while (IS_BLANK(*str)) str++;
8209 while (*str != 0) {
8210 if (IS_BLANK(*str)) {
8211 while (IS_BLANK(*str)) str++;
8212 if (*str == 0)
8213 break;
8214 *p++ = ' ';
8215 } else
8216 *p++ = *str++;
8217 }
8218 *p = 0;
8219 return(ret);
8220}
8221
8222/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008223 * xmlRelaxNGValidateDatatype:
8224 * @ctxt: a Relax-NG validation context
8225 * @value: the string value
8226 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008227 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008228 *
8229 * Validate the given value against the dataype
8230 *
8231 * Returns 0 if the validation succeeded or an error code.
8232 */
8233static int
8234xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008235 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008236 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008237 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008238 void *result = NULL;
8239 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008240
8241 if ((define == NULL) || (define->data == NULL)) {
8242 return(-1);
8243 }
8244 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008245 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008246 if ((define->attrs != NULL) &&
8247 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008248 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008249 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008250 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008251 }
8252 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008253 ret = -1;
8254 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008255 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008256 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8257 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008258 return(-1);
8259 } else if (ret == 1) {
8260 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008261 } else if (ret == 2) {
8262 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008263 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008264 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008265 ret = -1;
8266 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008267 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008268 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8269 if (lib->facet != NULL) {
8270 tmp = lib->facet(lib->data, define->name, cur->name,
8271 cur->value, value, result);
8272 if (tmp != 0)
8273 ret = -1;
8274 }
8275 cur = cur->next;
8276 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008277 if ((ret == 0) && (define->content != NULL)) {
8278 const xmlChar *oldvalue, *oldendvalue;
8279
8280 oldvalue = ctxt->state->value;
8281 oldendvalue = ctxt->state->endvalue;
8282 ctxt->state->value = (xmlChar *) value;
8283 ctxt->state->endvalue = NULL;
8284 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8285 ctxt->state->value = (xmlChar *) oldvalue;
8286 ctxt->state->endvalue = (xmlChar *) oldendvalue;
8287 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008288 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8289 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008290 return(ret);
8291}
8292
8293/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008294 * xmlRelaxNGNextValue:
8295 * @ctxt: a Relax-NG validation context
8296 *
8297 * Skip to the next value when validating within a list
8298 *
8299 * Returns 0 if the operation succeeded or an error code.
8300 */
8301static int
8302xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
8303 xmlChar *cur;
8304
8305 cur = ctxt->state->value;
8306 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8307 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00008308 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008309 return(0);
8310 }
8311 while (*cur != 0) cur++;
8312 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
8313 if (cur == ctxt->state->endvalue)
8314 ctxt->state->value = NULL;
8315 else
8316 ctxt->state->value = cur;
8317 return(0);
8318}
8319
8320/**
8321 * xmlRelaxNGValidateValueList:
8322 * @ctxt: a Relax-NG validation context
8323 * @defines: the list of definitions to verify
8324 *
8325 * Validate the given set of definitions for the current value
8326 *
8327 * Returns 0 if the validation succeeded or an error code.
8328 */
8329static int
8330xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8331 xmlRelaxNGDefinePtr defines) {
8332 int ret = 0;
8333
8334 while (defines != NULL) {
8335 ret = xmlRelaxNGValidateValue(ctxt, defines);
8336 if (ret != 0)
8337 break;
8338 defines = defines->next;
8339 }
8340 return(ret);
8341}
8342
8343/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008344 * xmlRelaxNGValidateValue:
8345 * @ctxt: a Relax-NG validation context
8346 * @define: the definition to verify
8347 *
8348 * Validate the given definition for the current value
8349 *
8350 * Returns 0 if the validation succeeded or an error code.
8351 */
8352static int
8353xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8354 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00008355 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008356 xmlChar *value;
8357
8358 value = ctxt->state->value;
8359 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008360 case XML_RELAXNG_EMPTY: {
8361 if ((value != NULL) && (value[0] != 0)) {
8362 int idx = 0;
8363
8364 while (IS_BLANK(value[idx]))
8365 idx++;
8366 if (value[idx] != 0)
8367 ret = -1;
8368 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008369 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00008370 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008371 case XML_RELAXNG_TEXT:
8372 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00008373 case XML_RELAXNG_VALUE: {
8374 if (!xmlStrEqual(value, define->value)) {
8375 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008376 xmlRelaxNGTypeLibraryPtr lib;
8377
8378 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00008379 if ((lib != NULL) && (lib->comp != NULL)) {
8380 ret = lib->comp(lib->data, define->name,
8381 define->value, define->node,
8382 (void *) define->attrs,
8383 value, ctxt->state->node);
8384 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00008385 ret = -1;
8386 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008387 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008388 return(-1);
8389 } else if (ret == 1) {
8390 ret = 0;
8391 } else {
8392 ret = -1;
8393 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008394 } else {
8395 xmlChar *nval, *nvalue;
8396
8397 /*
8398 * TODO: trivial optimizations are possible by
8399 * computing at compile-time
8400 */
8401 nval = xmlRelaxNGNormalize(ctxt, define->value);
8402 nvalue = xmlRelaxNGNormalize(ctxt, value);
8403
Daniel Veillardea3f3982003-01-26 19:45:18 +00008404 if ((nval == NULL) || (nvalue == NULL) ||
8405 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00008406 ret = -1;
8407 if (nval != NULL)
8408 xmlFree(nval);
8409 if (nvalue != NULL)
8410 xmlFree(nvalue);
8411 }
8412 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008413 if (ret == 0)
8414 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00008415 break;
8416 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008417 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008418 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8419 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008420 if (ret == 0)
8421 xmlRelaxNGNextValue(ctxt);
8422
8423 break;
8424 }
8425 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008426 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008427 xmlChar *oldvalue;
8428
8429 oldflags = ctxt->flags;
8430 ctxt->flags |= FLAGS_IGNORABLE;
8431
8432 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008433 while (list != NULL) {
8434 ret = xmlRelaxNGValidateValue(ctxt, list);
8435 if (ret == 0) {
8436 break;
8437 }
8438 ctxt->state->value = oldvalue;
8439 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008440 }
8441 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008442 if (ret != 0) {
8443 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8444 xmlRelaxNGDumpValidError(ctxt);
8445 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008446 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008447 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008448 if (ret == 0)
8449 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008450 break;
8451 }
8452 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008453 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008454 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00008455#ifdef DEBUG_LIST
8456 int nb_values = 0;
8457#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008458
8459 oldvalue = ctxt->state->value;
8460 oldend = ctxt->state->endvalue;
8461
8462 val = xmlStrdup(oldvalue);
8463 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008464 val = xmlStrdup(BAD_CAST "");
8465 }
8466 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008467 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008468 return(-1);
8469 }
8470 cur = val;
8471 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00008472 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008473 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008474 cur++;
8475#ifdef DEBUG_LIST
8476 nb_values++;
8477#endif
8478 while (IS_BLANK(*cur))
8479 *cur++ = 0;
8480 } else
8481 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008482 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008483#ifdef DEBUG_LIST
8484 xmlGenericError(xmlGenericErrorContext,
8485 "list value: '%s' found %d items\n", oldvalue, nb_values);
8486 nb_values = 0;
8487#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008488 ctxt->state->endvalue = cur;
8489 cur = val;
8490 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008491
Daniel Veillardfd573f12003-03-16 17:52:32 +00008492 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008493
Daniel Veillardfd573f12003-03-16 17:52:32 +00008494 while (list != NULL) {
8495 if (ctxt->state->value == ctxt->state->endvalue)
8496 ctxt->state->value = NULL;
8497 ret = xmlRelaxNGValidateValue(ctxt, list);
8498 if (ret != 0) {
8499#ifdef DEBUG_LIST
8500 xmlGenericError(xmlGenericErrorContext,
8501 "Failed to validate value: '%s' with %d rule\n",
8502 ctxt->state->value, nb_values);
8503#endif
8504 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008505 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008506#ifdef DEBUG_LIST
8507 nb_values++;
8508#endif
8509 list = list->next;
8510 }
8511
8512 if ((ret == 0) && (ctxt->state->value != NULL) &&
8513 (ctxt->state->value != ctxt->state->endvalue)) {
8514 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
8515 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008516 }
8517 xmlFree(val);
8518 ctxt->state->value = oldvalue;
8519 ctxt->state->endvalue = oldend;
8520 break;
8521 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008522 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008523 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8524 if (ret != 0) {
8525 break;
8526 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008527 /* no break on purpose */
8528 case XML_RELAXNG_ZEROORMORE: {
8529 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008530
8531 oldflags = ctxt->flags;
8532 ctxt->flags |= FLAGS_IGNORABLE;
8533 cur = ctxt->state->value;
8534 temp = NULL;
8535 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8536 (temp != cur)) {
8537 temp = cur;
8538 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8539 if (ret != 0) {
8540 ctxt->state->value = temp;
8541 ret = 0;
8542 break;
8543 }
8544 cur = ctxt->state->value;
8545 }
8546 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008547 if (ret != 0) {
8548 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8549 xmlRelaxNGDumpValidError(ctxt);
8550 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008551 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008552 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008553 break;
8554 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008555 case XML_RELAXNG_EXCEPT: {
8556 xmlRelaxNGDefinePtr list;
8557
8558 list = define->content;
8559 while (list != NULL) {
8560 ret = xmlRelaxNGValidateValue(ctxt, list);
8561 if (ret == 0) {
8562 ret = -1;
8563 break;
8564 } else
8565 ret = 0;
8566 list = list->next;
8567 }
8568 break;
8569 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008570 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008571 case XML_RELAXNG_GROUP: {
8572 xmlRelaxNGDefinePtr list;
8573
8574 list = define->content;
8575 while (list != NULL) {
8576 ret = xmlRelaxNGValidateValue(ctxt, list);
8577 if (ret != 0) {
8578 ret = -1;
8579 break;
8580 } else
8581 ret = 0;
8582 list = list->next;
8583 }
Daniel Veillardd4310742003-02-18 21:12:46 +00008584 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008585 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008586 case XML_RELAXNG_REF:
8587 case XML_RELAXNG_PARENTREF:
8588 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8589 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008590 default:
8591 TODO
8592 ret = -1;
8593 }
8594 return(ret);
8595}
8596
8597/**
8598 * xmlRelaxNGValidateValueContent:
8599 * @ctxt: a Relax-NG validation context
8600 * @defines: the list of definitions to verify
8601 *
8602 * Validate the given definitions for the current value
8603 *
8604 * Returns 0 if the validation succeeded or an error code.
8605 */
8606static int
8607xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8608 xmlRelaxNGDefinePtr defines) {
8609 int ret = 0;
8610
8611 while (defines != NULL) {
8612 ret = xmlRelaxNGValidateValue(ctxt, defines);
8613 if (ret != 0)
8614 break;
8615 defines = defines->next;
8616 }
8617 return(ret);
8618}
8619
8620/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008621 * xmlRelaxNGAttributeMatch:
8622 * @ctxt: a Relax-NG validation context
8623 * @define: the definition to check
8624 * @prop: the attribute
8625 *
8626 * Check if the attribute matches the definition nameClass
8627 *
8628 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8629 */
8630static int
8631xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8632 xmlRelaxNGDefinePtr define,
8633 xmlAttrPtr prop) {
8634 int ret;
8635
8636 if (define->name != NULL) {
8637 if (!xmlStrEqual(define->name, prop->name))
8638 return(0);
8639 }
8640 if (define->ns != NULL) {
8641 if (define->ns[0] == 0) {
8642 if (prop->ns != NULL)
8643 return(0);
8644 } else {
8645 if ((prop->ns == NULL) ||
8646 (!xmlStrEqual(define->ns, prop->ns->href)))
8647 return(0);
8648 }
8649 }
8650 if (define->nameClass == NULL)
8651 return(1);
8652 define = define->nameClass;
8653 if (define->type == XML_RELAXNG_EXCEPT) {
8654 xmlRelaxNGDefinePtr list;
8655
8656 list = define->content;
8657 while (list != NULL) {
8658 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8659 if (ret == 1)
8660 return(0);
8661 if (ret < 0)
8662 return(ret);
8663 list = list->next;
8664 }
8665 } else {
8666 TODO
8667 }
8668 return(1);
8669}
8670
8671/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008672 * xmlRelaxNGValidateAttribute:
8673 * @ctxt: a Relax-NG validation context
8674 * @define: the definition to verify
8675 *
8676 * Validate the given attribute definition for that node
8677 *
8678 * Returns 0 if the validation succeeded or an error code.
8679 */
8680static int
8681xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8682 xmlRelaxNGDefinePtr define) {
8683 int ret = 0, i;
8684 xmlChar *value, *oldvalue;
8685 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008686 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008687
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008688 if (ctxt->state->nbAttrLeft <= 0)
8689 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008690 if (define->name != NULL) {
8691 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8692 tmp = ctxt->state->attrs[i];
8693 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8694 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8695 (tmp->ns == NULL)) ||
8696 ((tmp->ns != NULL) &&
8697 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8698 prop = tmp;
8699 break;
8700 }
8701 }
8702 }
8703 if (prop != NULL) {
8704 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8705 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008706 oldseq = ctxt->state->seq;
8707 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008708 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00008709 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008710 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008711 if (ctxt->state->value != NULL)
8712 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008713 if (value != NULL)
8714 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008715 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008716 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008717 if (ret == 0) {
8718 /*
8719 * flag the attribute as processed
8720 */
8721 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008722 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008723 }
8724 } else {
8725 ret = -1;
8726 }
8727#ifdef DEBUG
8728 xmlGenericError(xmlGenericErrorContext,
8729 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8730#endif
8731 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008732 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8733 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00008734 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00008735 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008736 prop = tmp;
8737 break;
8738 }
8739 }
8740 if (prop != NULL) {
8741 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8742 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008743 oldseq = ctxt->state->seq;
8744 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008745 ctxt->state->value = value;
8746 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008747 if (ctxt->state->value != NULL)
8748 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008749 if (value != NULL)
8750 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008751 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008752 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008753 if (ret == 0) {
8754 /*
8755 * flag the attribute as processed
8756 */
8757 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008758 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008759 }
8760 } else {
8761 ret = -1;
8762 }
8763#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00008764 if (define->ns != NULL) {
8765 xmlGenericError(xmlGenericErrorContext,
8766 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8767 define->ns, ret);
8768 } else {
8769 xmlGenericError(xmlGenericErrorContext,
8770 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8771 ret);
8772 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008773#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008774 }
8775
8776 return(ret);
8777}
8778
8779/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008780 * xmlRelaxNGValidateAttributeList:
8781 * @ctxt: a Relax-NG validation context
8782 * @define: the list of definition to verify
8783 *
8784 * Validate the given node against the list of attribute definitions
8785 *
8786 * Returns 0 if the validation succeeded or an error code.
8787 */
8788static int
8789xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8790 xmlRelaxNGDefinePtr defines) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00008791 int ret = 0, res;
8792 int needmore = 0;
8793 xmlRelaxNGDefinePtr cur;
8794
8795 cur = defines;
8796 while (cur != NULL) {
8797 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
8798 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8799 ret = -1;
8800 } else
8801 needmore = 1;
8802 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008803 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008804 if (!needmore)
8805 return(ret);
8806 cur = defines;
8807 while (cur != NULL) {
8808 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
8809 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8810 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8811 if (res < 0)
8812 ret = -1;
8813 } else {
8814 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8815 return(-1);
8816 }
8817 if (res == -1) /* continues on -2 */
8818 break;
8819 }
8820 cur = cur->next;
8821 }
8822
Daniel Veillardfd573f12003-03-16 17:52:32 +00008823 return(ret);
8824}
8825
8826/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008827 * xmlRelaxNGNodeMatchesList:
8828 * @node: the node
8829 * @list: a NULL terminated array of definitions
8830 *
8831 * Check if a node can be matched by one of the definitions
8832 *
8833 * Returns 1 if matches 0 otherwise
8834 */
8835static int
8836xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8837 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008838 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008839
8840 if ((node == NULL) || (list == NULL))
8841 return(0);
8842
8843 cur = list[i++];
8844 while (cur != NULL) {
8845 if ((node->type == XML_ELEMENT_NODE) &&
8846 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008847 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8848 if (tmp == 1)
8849 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008850 } else if (((node->type == XML_TEXT_NODE) ||
8851 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008852 (cur->type == XML_RELAXNG_TEXT)) {
8853 return(1);
8854 }
8855 cur = list[i++];
8856 }
8857 return(0);
8858}
8859
8860/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008861 * xmlRelaxNGValidateInterleave:
8862 * @ctxt: a Relax-NG validation context
8863 * @define: the definition to verify
8864 *
8865 * Validate an interleave definition for a node.
8866 *
8867 * Returns 0 if the validation succeeded or an error code.
8868 */
8869static int
8870xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
8871 xmlRelaxNGDefinePtr define) {
8872 int ret = 0, i, nbgroups, left;
8873 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008874 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008875
8876 xmlRelaxNGValidStatePtr oldstate;
8877 xmlRelaxNGPartitionPtr partitions;
8878 xmlRelaxNGInterleaveGroupPtr group = NULL;
8879 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8880 xmlNodePtr *list = NULL, *lasts = NULL;
8881
8882 if (define->data != NULL) {
8883 partitions = (xmlRelaxNGPartitionPtr) define->data;
8884 nbgroups = partitions->nbgroups;
8885 left = nbgroups;
8886 } else {
8887 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8888 return(-1);
8889 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008890 /*
8891 * Optimizations for MIXED
8892 */
8893 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00008894 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008895 ctxt->flags |= FLAGS_MIXED_CONTENT;
8896 if (nbgroups == 2) {
8897 /*
8898 * this is a pure <mixed> case
8899 */
8900 if (ctxt->state != NULL)
8901 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8902 ctxt->state->seq);
8903 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8904 ret = xmlRelaxNGValidateDefinition(ctxt,
8905 partitions->groups[1]->rule);
8906 else
8907 ret = xmlRelaxNGValidateDefinition(ctxt,
8908 partitions->groups[0]->rule);
8909 if (ret == 0) {
8910 if (ctxt->state != NULL)
8911 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8912 ctxt->state->seq);
8913 }
8914 ctxt->flags = oldflags;
8915 return(ret);
8916 }
8917 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008918
8919 /*
8920 * Build arrays to store the first and last node of the chain
8921 * pertaining to each group
8922 */
8923 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8924 if (list == NULL) {
8925 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8926 return(-1);
8927 }
8928 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8929 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8930 if (lasts == NULL) {
8931 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8932 return(-1);
8933 }
8934 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8935
8936 /*
8937 * Walk the sequence of children finding the right group and
8938 * sorting them in sequences.
8939 */
8940 cur = ctxt->state->seq;
8941 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8942 start = cur;
8943 while (cur != NULL) {
8944 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008945 if ((partitions->triage != NULL) &&
8946 (partitions->flags & IS_DETERMINIST)) {
8947 void *tmp = NULL;
8948
8949 if ((cur->type == XML_TEXT_NODE) ||
8950 (cur->type == XML_CDATA_SECTION_NODE)) {
8951 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8952 NULL);
8953 } else if (cur->type == XML_ELEMENT_NODE) {
8954 if (cur->ns != NULL) {
8955 tmp = xmlHashLookup2(partitions->triage, cur->name,
8956 cur->ns->href);
8957 if (tmp == NULL)
8958 tmp = xmlHashLookup2(partitions->triage,
8959 BAD_CAST "#any", cur->ns->href);
8960 } else
8961 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
8962 if (tmp == NULL)
8963 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
8964 NULL);
8965 }
8966
8967 if (tmp == NULL) {
8968 i = nbgroups;
8969 } else {
8970 i = ((long) tmp) - 1;
8971 if (partitions->flags & IS_NEEDCHECK) {
8972 group = partitions->groups[i];
8973 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
8974 i = nbgroups;
8975 }
8976 }
8977 } else {
8978 for (i = 0;i < nbgroups;i++) {
8979 group = partitions->groups[i];
8980 if (group == NULL)
8981 continue;
8982 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
8983 break;
8984 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008985 }
8986 /*
8987 * We break as soon as an element not matched is found
8988 */
8989 if (i >= nbgroups) {
8990 break;
8991 }
8992 if (lasts[i] != NULL) {
8993 lasts[i]->next = cur;
8994 lasts[i] = cur;
8995 } else {
8996 list[i] = cur;
8997 lasts[i] = cur;
8998 }
8999 if (cur->next != NULL)
9000 lastchg = cur->next;
9001 else
9002 lastchg = cur;
9003 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9004 }
9005 if (ret != 0) {
9006 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9007 ret = -1;
9008 goto done;
9009 }
9010 lastelem = cur;
9011 oldstate = ctxt->state;
9012 for (i = 0;i < nbgroups;i++) {
9013 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9014 group = partitions->groups[i];
9015 if (lasts[i] != NULL) {
9016 last = lasts[i]->next;
9017 lasts[i]->next = NULL;
9018 }
9019 ctxt->state->seq = list[i];
9020 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9021 if (ret != 0)
9022 break;
9023 if (ctxt->state != NULL) {
9024 cur = ctxt->state->seq;
9025 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00009026 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009027 oldstate = ctxt->state;
9028 ctxt->state = NULL;
9029 if (cur != NULL) {
9030 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9031 ret = -1;
9032 ctxt->state = oldstate;
9033 goto done;
9034 }
9035 } else if (ctxt->states != NULL) {
9036 int j;
9037 int found = 0;
9038
9039 for (j = 0;j < ctxt->states->nbState;j++) {
9040 cur = ctxt->states->tabState[j]->seq;
9041 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9042 if (cur == NULL) {
9043 found = 1;
9044 break;
9045 }
9046 }
9047 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009048 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009049 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
9050 }
9051 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009052 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009053 }
9054 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9055 ctxt->states = NULL;
9056 if (found == 0) {
9057 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9058 ret = -1;
9059 ctxt->state = oldstate;
9060 goto done;
9061 }
9062 } else {
9063 ret = -1;
9064 break;
9065 }
9066 if (lasts[i] != NULL) {
9067 lasts[i]->next = last;
9068 }
9069 }
9070 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009071 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009072 ctxt->state = oldstate;
9073 ctxt->state->seq = lastelem;
9074 if (ret != 0) {
9075 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9076 ret = -1;
9077 goto done;
9078 }
9079
9080done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009081 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009082 /*
9083 * builds the next links chain from the prev one
9084 */
9085 cur = lastchg;
9086 while (cur != NULL) {
9087 if ((cur == start) || (cur->prev == NULL))
9088 break;
9089 cur->prev->next = cur;
9090 cur = cur->prev;
9091 }
9092 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00009093 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009094 }
9095
9096 xmlFree(list);
9097 xmlFree(lasts);
9098 return(ret);
9099}
9100
9101/**
9102 * xmlRelaxNGValidateDefinitionList:
9103 * @ctxt: a Relax-NG validation context
9104 * @define: the list of definition to verify
9105 *
9106 * Validate the given node content against the (list) of definitions
9107 *
9108 * Returns 0 if the validation succeeded or an error code.
9109 */
9110static int
9111xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9112 xmlRelaxNGDefinePtr defines) {
9113 int ret = 0, res;
9114
9115
Daniel Veillard952379b2003-03-17 15:37:12 +00009116 if (defines == NULL) {
9117 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
9118 return(-1);
9119 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009120 while (defines != NULL) {
9121 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9122 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9123 if (res < 0)
9124 ret = -1;
9125 } else {
9126 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9127 return(-1);
9128 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009129 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00009130 break;
9131 defines = defines->next;
9132 }
9133
9134 return(ret);
9135}
9136
9137/**
9138 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009139 * @ctxt: a Relax-NG validation context
9140 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009141 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009142 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009143 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009144 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009145 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009146 */
9147static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009148xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9149 xmlRelaxNGDefinePtr define,
9150 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00009151 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009152
Daniel Veillardfd573f12003-03-16 17:52:32 +00009153 if (define->name != NULL) {
9154 if (!xmlStrEqual(elem->name, define->name)) {
9155 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9156 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009157 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009158 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009159 if ((define->ns != NULL) && (define->ns[0] != 0)) {
9160 if (elem->ns == NULL) {
9161 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
9162 elem->name);
9163 return(0);
9164 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9165 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9166 elem->name, define->ns);
9167 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009168 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009169 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9170 (define->name == NULL)) {
9171 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9172 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009173 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009174 } else if ((elem->ns != NULL) && (define->name != NULL)) {
9175 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9176 define->name);
9177 return(0);
9178 }
9179
9180 if (define->nameClass == NULL)
9181 return(1);
9182
9183 define = define->nameClass;
9184 if (define->type == XML_RELAXNG_EXCEPT) {
9185 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009186 if (ctxt != NULL) {
9187 oldflags = ctxt->flags;
9188 ctxt->flags |= FLAGS_IGNORABLE;
9189 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009190
9191 list = define->content;
9192 while (list != NULL) {
9193 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9194 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009195 if (ctxt != NULL)
9196 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009197 return(0);
9198 }
9199 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009200 if (ctxt != NULL)
9201 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009202 return(ret);
9203 }
9204 list = list->next;
9205 }
9206 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009207 if (ctxt != NULL) {
9208 ctxt->flags = oldflags;
9209 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009210 } else if (define->type == XML_RELAXNG_CHOICE) {
9211 xmlRelaxNGDefinePtr list;
9212
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009213 if (ctxt != NULL) {
9214 oldflags = ctxt->flags;
9215 ctxt->flags |= FLAGS_IGNORABLE;
9216 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009217
9218 list = define->nameClass;
9219 while (list != NULL) {
9220 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9221 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009222 if (ctxt != NULL)
9223 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009224 return(1);
9225 }
9226 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009227 if (ctxt != NULL)
9228 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009229 return(ret);
9230 }
9231 list = list->next;
9232 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009233 if (ctxt != NULL) {
9234 if (ret != 0) {
9235 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9236 xmlRelaxNGDumpValidError(ctxt);
9237 } else {
9238 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
9239 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009240 }
9241 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009242 if (ctxt != NULL) {
9243 ctxt->flags = oldflags;
9244 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009245 } else {
9246 TODO
9247 ret = -1;
9248 }
9249 return(ret);
9250}
9251
9252/**
9253 * xmlRelaxNGValidateElementEnd:
9254 * @ctxt: a Relax-NG validation context
9255 *
9256 * Validate the end of the element, implements check that
9257 * there is nothing left not consumed in the element content
9258 * or in the attribute list.
9259 *
9260 * Returns 0 if the validation succeeded or an error code.
9261 */
9262static int
9263xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
9264 int ret = 0, i;
9265 xmlRelaxNGValidStatePtr state;
9266
9267 state = ctxt->state;
9268 if (state->seq != NULL) {
9269 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9270 if (state->seq != NULL) {
9271 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9272 state->node->name, state->seq->name);
9273 ret = -1;
9274 }
9275 }
9276 for (i = 0;i < state->nbAttrs;i++) {
9277 if (state->attrs[i] != NULL) {
9278 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9279 state->attrs[i]->name, state->node->name);
9280 ret = -1;
9281 }
9282 }
9283 return(ret);
9284}
9285
9286/**
9287 * xmlRelaxNGValidateState:
9288 * @ctxt: a Relax-NG validation context
9289 * @define: the definition to verify
9290 *
9291 * Validate the current state against the definition
9292 *
9293 * Returns 0 if the validation succeeded or an error code.
9294 */
9295static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009296xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9297 xmlRelaxNGDefinePtr define)
9298{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009299 xmlNodePtr node;
9300 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009301 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009302
9303 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009304 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9305 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009306 }
9307
9308 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009309 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009310 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009311 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009312 }
9313#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009314 for (i = 0; i < ctxt->depth; i++)
9315 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009316 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009317 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009318 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009319 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009320 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009321 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009322 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009323 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009324#endif
9325 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009326 switch (define->type) {
9327 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009328 node = xmlRelaxNGSkipIgnored(ctxt, node);
9329 ret = 0;
9330 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009331 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009332 ret = -1;
9333 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009334 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009335 while ((node != NULL) &&
9336 ((node->type == XML_TEXT_NODE) ||
9337 (node->type == XML_COMMENT_NODE) ||
9338 (node->type == XML_PI_NODE) ||
9339 (node->type == XML_CDATA_SECTION_NODE)))
9340 node = node->next;
9341 ctxt->state->seq = node;
9342 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009343 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009344 errNr = ctxt->errNr;
9345 node = xmlRelaxNGSkipIgnored(ctxt, node);
9346 if (node == NULL) {
9347 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9348 ret = -1;
9349 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9350 xmlRelaxNGDumpValidError(ctxt);
9351 break;
9352 }
9353 if (node->type != XML_ELEMENT_NODE) {
9354 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9355 ret = -1;
9356 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9357 xmlRelaxNGDumpValidError(ctxt);
9358 break;
9359 }
9360 /*
9361 * This node was already validated successfully against
9362 * this definition.
9363 */
9364 if (node->_private == define) {
9365 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9366 if (ctxt->errNr > errNr)
9367 xmlRelaxNGPopErrors(ctxt, errNr);
9368 if (ctxt->errNr != 0) {
9369 while ((ctxt->err != NULL) &&
9370 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9371 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9372 ||
9373 ((ctxt->err->err ==
9374 XML_RELAXNG_ERR_ELEMEXTRANS)
9375 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9376 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9377 || (ctxt->err->err ==
9378 XML_RELAXNG_ERR_NOTELEM)))
9379 xmlRelaxNGValidErrorPop(ctxt);
9380 }
9381 break;
9382 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009383
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009384 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9385 if (ret <= 0) {
9386 ret = -1;
9387 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9388 xmlRelaxNGDumpValidError(ctxt);
9389 break;
9390 }
9391 ret = 0;
9392 if (ctxt->errNr != 0) {
9393 if (ctxt->errNr > errNr)
9394 xmlRelaxNGPopErrors(ctxt, errNr);
9395 while ((ctxt->err != NULL) &&
9396 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9397 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9398 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9399 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9400 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9401 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9402 xmlRelaxNGValidErrorPop(ctxt);
9403 }
9404 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009405
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009406 oldflags = ctxt->flags;
9407 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9408 ctxt->flags -= FLAGS_MIXED_CONTENT;
9409 }
9410 state = xmlRelaxNGNewValidState(ctxt, node);
9411 if (state == NULL) {
9412 ret = -1;
9413 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9414 xmlRelaxNGDumpValidError(ctxt);
9415 break;
9416 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009417
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009418 oldstate = ctxt->state;
9419 ctxt->state = state;
9420 if (define->attrs != NULL) {
9421 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9422 if (tmp != 0) {
9423 ret = -1;
9424 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9425 }
9426 }
9427 if (define->contModel != NULL) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009428 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9429 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9430 xmlNodePtr nseq;
9431
9432 nstate = xmlRelaxNGNewValidState(ctxt, node);
9433 ctxt->state = nstate;
9434 ctxt->states = NULL;
9435
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009436 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9437 define->contModel,
9438 ctxt->state->seq);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009439 nseq = ctxt->state->seq;
9440 ctxt->state = tmpstate;
9441 ctxt->states = tmpstates;
9442 xmlRelaxNGFreeValidState(ctxt, nstate);
9443
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009444#ifdef DEBUG_COMPILE
9445 xmlGenericError(xmlGenericErrorContext,
9446 "Validating content of '%s' : %d\n", define->name, tmp);
9447#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009448 if (tmp != 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009449 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009450
9451 if (ctxt->states != NULL) {
9452 tmp = -1;
9453
9454 ctxt->flags |= FLAGS_IGNORABLE;
9455
9456 for (i = 0; i < ctxt->states->nbState; i++) {
9457 state = ctxt->states->tabState[i];
9458 ctxt->state = state;
9459 ctxt->state->seq = nseq;
9460
9461 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9462 tmp = 0;
9463 xmlRelaxNGFreeValidState(ctxt, state);
9464 }
9465 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9466 ctxt->flags = oldflags;
9467 ctxt->states = NULL;
9468 if ((ret == 0) && (tmp == -1))
9469 ret = -1;
9470 } else {
9471 state = ctxt->state;
9472 ctxt->state->seq = nseq;
9473 if (ret == 0)
9474 ret = xmlRelaxNGValidateElementEnd(ctxt);
9475 xmlRelaxNGFreeValidState(ctxt, state);
9476 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009477 } else {
9478 if (define->content != NULL) {
9479 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9480 define->content);
9481 if (tmp != 0) {
9482 ret = -1;
9483 if (ctxt->state == NULL) {
9484 ctxt->state = oldstate;
9485 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9486 node->name);
9487 ctxt->state = NULL;
9488 } else {
9489 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9490 node->name);
9491 }
9492
9493 }
9494 }
9495 if (ctxt->states != NULL) {
9496 tmp = -1;
9497
9498 ctxt->flags |= FLAGS_IGNORABLE;
9499
9500 for (i = 0; i < ctxt->states->nbState; i++) {
9501 state = ctxt->states->tabState[i];
9502 ctxt->state = state;
9503
9504 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9505 tmp = 0;
9506 xmlRelaxNGFreeValidState(ctxt, state);
9507 }
9508 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9509 ctxt->flags = oldflags;
9510 ctxt->states = NULL;
9511 if ((ret == 0) && (tmp == -1))
9512 ret = -1;
9513 } else {
9514 state = ctxt->state;
9515 if (ret == 0)
9516 ret = xmlRelaxNGValidateElementEnd(ctxt);
9517 xmlRelaxNGFreeValidState(ctxt, state);
9518 }
9519 }
9520 if (ret == 0) {
9521 node->_private = define;
9522 }
9523 ctxt->flags = oldflags;
9524 ctxt->state = oldstate;
9525 if (oldstate != NULL)
9526 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9527 if (ret != 0) {
9528 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9529 xmlRelaxNGDumpValidError(ctxt);
9530 ret = 0;
9531 } else {
9532 ret = -2;
9533 }
9534 } else {
9535 if (ctxt->errNr > errNr)
9536 xmlRelaxNGPopErrors(ctxt, errNr);
9537 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009538
9539#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009540 xmlGenericError(xmlGenericErrorContext,
9541 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9542 node->name, ret);
9543 if (oldstate == NULL)
9544 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9545 else if (oldstate->seq == NULL)
9546 xmlGenericError(xmlGenericErrorContext, ": done\n");
9547 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9548 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9549 oldstate->seq->name);
9550 else
9551 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9552 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009553#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009554 break;
9555 case XML_RELAXNG_OPTIONAL:{
9556 errNr = ctxt->errNr;
9557 oldflags = ctxt->flags;
9558 ctxt->flags |= FLAGS_IGNORABLE;
9559 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9560 ret =
9561 xmlRelaxNGValidateDefinitionList(ctxt,
9562 define->content);
9563 if (ret != 0) {
9564 if (ctxt->state != NULL)
9565 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9566 ctxt->state = oldstate;
9567 ctxt->flags = oldflags;
9568 ret = 0;
9569 if (ctxt->errNr > errNr)
9570 xmlRelaxNGPopErrors(ctxt, errNr);
9571 break;
9572 }
9573 if (ctxt->states != NULL) {
9574 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9575 } else {
9576 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9577 if (ctxt->states == NULL) {
9578 xmlRelaxNGFreeValidState(ctxt, oldstate);
9579 ctxt->flags = oldflags;
9580 ret = -1;
9581 if (ctxt->errNr > errNr)
9582 xmlRelaxNGPopErrors(ctxt, errNr);
9583 break;
9584 }
9585 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9586 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9587 ctxt->state = NULL;
9588 }
9589 ctxt->flags = oldflags;
9590 ret = 0;
9591 if (ctxt->errNr > errNr)
9592 xmlRelaxNGPopErrors(ctxt, errNr);
9593 break;
9594 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009595 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009596 errNr = ctxt->errNr;
9597 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9598 if (ret != 0) {
9599 break;
9600 }
9601 if (ctxt->errNr > errNr)
9602 xmlRelaxNGPopErrors(ctxt, errNr);
9603 /* no break on purpose */
9604 case XML_RELAXNG_ZEROORMORE:{
9605 int progress;
9606 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9607 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009608
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009609 errNr = ctxt->errNr;
9610 res = xmlRelaxNGNewStates(ctxt, 1);
9611 if (res == NULL) {
9612 ret = -1;
9613 break;
9614 }
9615 /*
9616 * All the input states are also exit states
9617 */
9618 if (ctxt->state != NULL) {
9619 xmlRelaxNGAddStates(ctxt, res,
9620 xmlRelaxNGCopyValidState(ctxt,
9621 ctxt->
9622 state));
9623 } else {
9624 for (j = 0; j < ctxt->states->nbState; j++) {
9625 xmlRelaxNGAddStates(ctxt, res,
9626 xmlRelaxNGCopyValidState(ctxt,
9627 ctxt->
9628 states->
9629 tabState
9630 [j]));
9631 }
9632 }
9633 oldflags = ctxt->flags;
9634 ctxt->flags |= FLAGS_IGNORABLE;
9635 do {
9636 progress = 0;
9637 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009638
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009639 if (ctxt->states != NULL) {
9640 states = ctxt->states;
9641 for (i = 0; i < states->nbState; i++) {
9642 ctxt->state = states->tabState[i];
9643 ctxt->states = NULL;
9644 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9645 define->
9646 content);
9647 if (ret == 0) {
9648 if (ctxt->state != NULL) {
9649 tmp = xmlRelaxNGAddStates(ctxt, res,
9650 ctxt->state);
9651 ctxt->state = NULL;
9652 if (tmp == 1)
9653 progress = 1;
9654 } else if (ctxt->states != NULL) {
9655 for (j = 0; j < ctxt->states->nbState;
9656 j++) {
9657 tmp =
9658 xmlRelaxNGAddStates(ctxt, res,
9659 ctxt->
9660 states->
9661 tabState
9662 [j]);
9663 if (tmp == 1)
9664 progress = 1;
9665 }
9666 xmlRelaxNGFreeStates(ctxt,
9667 ctxt->states);
9668 ctxt->states = NULL;
9669 }
9670 } else {
9671 if (ctxt->state != NULL) {
9672 xmlRelaxNGFreeValidState(ctxt,
9673 ctxt->state);
9674 ctxt->state = NULL;
9675 }
9676 }
9677 }
9678 } else {
9679 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9680 define->
9681 content);
9682 if (ret != 0) {
9683 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9684 ctxt->state = NULL;
9685 } else {
9686 base = res->nbState;
9687 if (ctxt->state != NULL) {
9688 tmp = xmlRelaxNGAddStates(ctxt, res,
9689 ctxt->state);
9690 ctxt->state = NULL;
9691 if (tmp == 1)
9692 progress = 1;
9693 } else if (ctxt->states != NULL) {
9694 for (j = 0; j < ctxt->states->nbState; j++) {
9695 tmp = xmlRelaxNGAddStates(ctxt, res,
9696 ctxt->
9697 states->
9698 tabState[j]);
9699 if (tmp == 1)
9700 progress = 1;
9701 }
9702 if (states == NULL) {
9703 states = ctxt->states;
9704 } else {
9705 xmlRelaxNGFreeStates(ctxt,
9706 ctxt->states);
9707 }
9708 ctxt->states = NULL;
9709 }
9710 }
9711 }
9712 if (progress) {
9713 /*
9714 * Collect all the new nodes added at that step
9715 * and make them the new node set
9716 */
9717 if (res->nbState - base == 1) {
9718 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9719 res->
9720 tabState
9721 [base]);
9722 } else {
9723 if (states == NULL) {
9724 xmlRelaxNGNewStates(ctxt,
9725 res->nbState - base);
9726 }
9727 states->nbState = 0;
9728 for (i = base; i < res->nbState; i++)
9729 xmlRelaxNGAddStates(ctxt, states,
9730 xmlRelaxNGCopyValidState
9731 (ctxt,
9732 res->tabState[i]));
9733 ctxt->states = states;
9734 }
9735 }
9736 } while (progress == 1);
9737 if (states != NULL) {
9738 xmlRelaxNGFreeStates(ctxt, states);
9739 }
9740 ctxt->states = res;
9741 ctxt->flags = oldflags;
9742 if (ctxt->errNr > errNr)
9743 xmlRelaxNGPopErrors(ctxt, errNr);
9744 ret = 0;
9745 break;
9746 }
9747 case XML_RELAXNG_CHOICE:{
9748 xmlRelaxNGDefinePtr list = NULL;
9749 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009750
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009751 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009752
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009753 errNr = ctxt->errNr;
9754 if ((define->dflags & IS_TRIABLE)
9755 && (define->data != NULL)) {
9756 xmlHashTablePtr triage =
9757 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +00009758
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009759 /*
9760 * Something we can optimize cleanly there is only one
9761 * possble branch out !
9762 */
9763 if (node == NULL) {
9764 ret = -1;
9765 break;
9766 }
9767 if ((node->type == XML_TEXT_NODE) ||
9768 (node->type == XML_CDATA_SECTION_NODE)) {
9769 list =
9770 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9771 } else if (node->type == XML_ELEMENT_NODE) {
9772 if (node->ns != NULL) {
9773 list = xmlHashLookup2(triage, node->name,
9774 node->ns->href);
9775 if (list == NULL)
9776 list =
9777 xmlHashLookup2(triage, BAD_CAST "#any",
9778 node->ns->href);
9779 } else
9780 list =
9781 xmlHashLookup2(triage, node->name, NULL);
9782 if (list == NULL)
9783 list =
9784 xmlHashLookup2(triage, BAD_CAST "#any",
9785 NULL);
9786 }
9787 if (list == NULL) {
9788 ret = -1;
9789 break;
9790 }
9791 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9792 if (ret == 0) {
9793 }
9794 break;
9795 }
Daniel Veillarde063f482003-03-21 16:53:17 +00009796
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009797 list = define->content;
9798 oldflags = ctxt->flags;
9799 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009800
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009801 while (list != NULL) {
9802 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9803 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9804 if (ret == 0) {
9805 if (states == NULL) {
9806 states = xmlRelaxNGNewStates(ctxt, 1);
9807 }
9808 if (ctxt->state != NULL) {
9809 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9810 } else if (ctxt->states != NULL) {
9811 for (i = 0; i < ctxt->states->nbState; i++) {
9812 xmlRelaxNGAddStates(ctxt, states,
9813 ctxt->states->
9814 tabState[i]);
9815 }
9816 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9817 ctxt->states = NULL;
9818 }
9819 } else {
9820 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9821 }
9822 ctxt->state = oldstate;
9823 list = list->next;
9824 }
9825 if (states != NULL) {
9826 xmlRelaxNGFreeValidState(ctxt, oldstate);
9827 ctxt->states = states;
9828 ctxt->state = NULL;
9829 ret = 0;
9830 } else {
9831 ctxt->states = NULL;
9832 }
9833 ctxt->flags = oldflags;
9834 if (ret != 0) {
9835 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9836 xmlRelaxNGDumpValidError(ctxt);
9837 }
9838 } else {
9839 if (ctxt->errNr > errNr)
9840 xmlRelaxNGPopErrors(ctxt, errNr);
9841 }
9842 break;
9843 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009844 case XML_RELAXNG_DEF:
9845 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009846 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9847 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009848 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009849 ret = xmlRelaxNGValidateInterleave(ctxt, define);
9850 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009851 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009852 ret = xmlRelaxNGValidateAttribute(ctxt, define);
9853 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +00009854 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009855 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00009856 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009857 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +00009858 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009859 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9860 break;
9861 case XML_RELAXNG_DATATYPE:{
9862 xmlNodePtr child;
9863 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009864
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009865 child = node;
9866 while (child != NULL) {
9867 if (child->type == XML_ELEMENT_NODE) {
9868 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9869 node->parent->name);
9870 ret = -1;
9871 break;
9872 } else if ((child->type == XML_TEXT_NODE) ||
9873 (child->type == XML_CDATA_SECTION_NODE)) {
9874 content = xmlStrcat(content, child->content);
9875 }
9876 /* TODO: handle entities ... */
9877 child = child->next;
9878 }
9879 if (ret == -1) {
9880 if (content != NULL)
9881 xmlFree(content);
9882 break;
9883 }
9884 if (content == NULL) {
9885 content = xmlStrdup(BAD_CAST "");
9886 if (content == NULL) {
9887 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9888 ret = -1;
9889 break;
9890 }
9891 }
9892 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9893 ctxt->state->seq);
9894 if (ret == -1) {
9895 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9896 } else if (ret == 0) {
9897 ctxt->state->seq = NULL;
9898 }
9899 if (content != NULL)
9900 xmlFree(content);
9901 break;
9902 }
9903 case XML_RELAXNG_VALUE:{
9904 xmlChar *content = NULL;
9905 xmlChar *oldvalue;
9906 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009907
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009908 child = node;
9909 while (child != NULL) {
9910 if (child->type == XML_ELEMENT_NODE) {
9911 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9912 node->parent->name);
9913 ret = -1;
9914 break;
9915 } else if ((child->type == XML_TEXT_NODE) ||
9916 (child->type == XML_CDATA_SECTION_NODE)) {
9917 content = xmlStrcat(content, child->content);
9918 }
9919 /* TODO: handle entities ... */
9920 child = child->next;
9921 }
9922 if (ret == -1) {
9923 if (content != NULL)
9924 xmlFree(content);
9925 break;
9926 }
9927 if (content == NULL) {
9928 content = xmlStrdup(BAD_CAST "");
9929 if (content == NULL) {
9930 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9931 ret = -1;
9932 break;
9933 }
9934 }
9935 oldvalue = ctxt->state->value;
9936 ctxt->state->value = content;
9937 ret = xmlRelaxNGValidateValue(ctxt, define);
9938 ctxt->state->value = oldvalue;
9939 if (ret == -1) {
9940 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9941 } else if (ret == 0) {
9942 ctxt->state->seq = NULL;
9943 }
9944 if (content != NULL)
9945 xmlFree(content);
9946 break;
9947 }
9948 case XML_RELAXNG_LIST:{
9949 xmlChar *content;
9950 xmlNodePtr child;
9951 xmlChar *oldvalue, *oldendvalue;
9952 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009953
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009954 /*
9955 * Make sure it's only text nodes
9956 */
9957
9958 content = NULL;
9959 child = node;
9960 while (child != NULL) {
9961 if (child->type == XML_ELEMENT_NODE) {
9962 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
9963 node->parent->name);
9964 ret = -1;
9965 break;
9966 } else if ((child->type == XML_TEXT_NODE) ||
9967 (child->type == XML_CDATA_SECTION_NODE)) {
9968 content = xmlStrcat(content, child->content);
9969 }
9970 /* TODO: handle entities ... */
9971 child = child->next;
9972 }
9973 if (ret == -1) {
9974 if (content != NULL)
9975 xmlFree(content);
9976 break;
9977 }
9978 if (content == NULL) {
9979 content = xmlStrdup(BAD_CAST "");
9980 if (content == NULL) {
9981 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9982 ret = -1;
9983 break;
9984 }
9985 }
9986 len = xmlStrlen(content);
9987 oldvalue = ctxt->state->value;
9988 oldendvalue = ctxt->state->endvalue;
9989 ctxt->state->value = content;
9990 ctxt->state->endvalue = content + len;
9991 ret = xmlRelaxNGValidateValue(ctxt, define);
9992 ctxt->state->value = oldvalue;
9993 ctxt->state->endvalue = oldendvalue;
9994 if (ret == -1) {
9995 VALID_ERR(XML_RELAXNG_ERR_LIST);
9996 } else if ((ret == 0) && (node != NULL)) {
9997 ctxt->state->seq = node->next;
9998 }
9999 if (content != NULL)
10000 xmlFree(content);
10001 break;
10002 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010003 case XML_RELAXNG_EXCEPT:
10004 case XML_RELAXNG_PARAM:
10005 TODO ret = -1;
10006 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010007 }
10008 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010009#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010010 for (i = 0; i < ctxt->depth; i++)
10011 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010012 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010013 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010014 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010015 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010016 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010017 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010018 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010019 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010020#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010021 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010022}
10023
10024/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010025 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010026 * @ctxt: a Relax-NG validation context
10027 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010028 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010029 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010030 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010031 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010032 */
10033static int
Daniel Veillardfd573f12003-03-16 17:52:32 +000010034xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10035 xmlRelaxNGDefinePtr define) {
10036 xmlRelaxNGStatesPtr states, res;
10037 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010038
Daniel Veillardfd573f12003-03-16 17:52:32 +000010039 /*
10040 * We should NOT have both ctxt->state and ctxt->states
10041 */
10042 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10043 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010044 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010045 ctxt->state = NULL;
10046 }
10047
10048 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10049 if (ctxt->states != NULL) {
10050 ctxt->state = ctxt->states->tabState[0];
10051 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10052 ctxt->states = NULL;
10053 }
10054 ret = xmlRelaxNGValidateState(ctxt, define);
10055 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10056 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010057 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010058 ctxt->state = NULL;
10059 }
10060 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10061 ctxt->state = ctxt->states->tabState[0];
10062 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10063 ctxt->states = NULL;
10064 }
10065 return(ret);
10066 }
10067
10068 states = ctxt->states;
10069 ctxt->states = NULL;
10070 res = NULL;
10071 j = 0;
10072 oldflags = ctxt->flags;
10073 ctxt->flags |= FLAGS_IGNORABLE;
10074 for (i = 0;i < states->nbState;i++) {
10075 ctxt->state = states->tabState[i];
10076 ctxt->states = NULL;
10077 ret = xmlRelaxNGValidateState(ctxt, define);
10078 /*
10079 * We should NOT have both ctxt->state and ctxt->states
10080 */
10081 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10082 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010083 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010084 ctxt->state = NULL;
10085 }
10086 if (ret == 0) {
10087 if (ctxt->states == NULL) {
10088 if (res != NULL) {
10089 /* add the state to the container */
10090 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10091 ctxt->state = NULL;
10092 } else {
10093 /* add the state directly in states */
10094 states->tabState[j++] = ctxt->state;
10095 ctxt->state = NULL;
10096 }
10097 } else {
10098 if (res == NULL) {
10099 /* make it the new container and copy other results */
10100 res = ctxt->states;
10101 ctxt->states = NULL;
10102 for (k = 0;k < j;k++)
10103 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
10104 } else {
10105 /* add all the new results to res and reff the container */
10106 for (k = 0;k < ctxt->states->nbState;k++)
10107 xmlRelaxNGAddStates(ctxt, res,
10108 ctxt->states->tabState[k]);
10109 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10110 ctxt->states = NULL;
10111 }
10112 }
10113 } else {
10114 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010115 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010116 ctxt->state = NULL;
10117 } else if (ctxt->states != NULL) {
10118 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +000010119 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010120 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10121 ctxt->states = NULL;
10122 }
10123 }
10124 }
10125 ctxt->flags = oldflags;
10126 if (res != NULL) {
10127 xmlRelaxNGFreeStates(ctxt, states);
10128 ctxt->states = res;
10129 ret = 0;
10130 } else if (j > 1) {
10131 states->nbState = j;
10132 ctxt->states = states;
10133 ret =0;
10134 } else if (j == 1) {
10135 ctxt->state = states->tabState[0];
10136 xmlRelaxNGFreeStates(ctxt, states);
10137 ret = 0;
10138 } else {
10139 ret = -1;
10140 xmlRelaxNGFreeStates(ctxt, states);
10141 if (ctxt->states != NULL) {
10142 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10143 ctxt->states = NULL;
10144 }
10145 }
10146 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10147 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010148 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010149 ctxt->state = NULL;
10150 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010151 return(ret);
10152}
10153
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010154/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010155 * xmlRelaxNGValidateDocument:
10156 * @ctxt: a Relax-NG validation context
10157 * @doc: the document
10158 *
10159 * Validate the given document
10160 *
10161 * Returns 0 if the validation succeeded or an error code.
10162 */
10163static int
10164xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10165 int ret;
10166 xmlRelaxNGPtr schema;
10167 xmlRelaxNGGrammarPtr grammar;
10168 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010169 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010170
10171 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10172 return(-1);
10173
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010174 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010175 schema = ctxt->schema;
10176 grammar = schema->topgrammar;
10177 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +000010178 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010179 return(-1);
10180 }
10181 state = xmlRelaxNGNewValidState(ctxt, NULL);
10182 ctxt->state = state;
10183 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010184 if ((ctxt->state != NULL) && (state->seq != NULL)) {
10185 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010186 node = state->seq;
10187 node = xmlRelaxNGSkipIgnored(ctxt, node);
10188 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +000010189 if (ret != -1) {
10190 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10191 ret = -1;
10192 }
10193 }
10194 } else if (ctxt->states != NULL) {
10195 int i;
10196 int tmp = -1;
10197
10198 for (i = 0;i < ctxt->states->nbState;i++) {
10199 state = ctxt->states->tabState[i];
10200 node = state->seq;
10201 node = xmlRelaxNGSkipIgnored(ctxt, node);
10202 if (node == NULL)
10203 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +000010204 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010205 }
10206 if (tmp == -1) {
10207 if (ret != -1) {
10208 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10209 ret = -1;
10210 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010211 }
10212 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010213 if (ctxt->state != NULL) {
10214 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10215 ctxt->state = NULL;
10216 }
Daniel Veillard580ced82003-03-21 21:22:48 +000010217 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +000010218 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010219#ifdef DEBUG
10220 else if (ctxt->errNr != 0) {
10221 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
10222 ctxt->errNr);
10223 xmlRelaxNGDumpValidError(ctxt);
10224 }
10225#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010226 if (ctxt->idref == 1) {
10227 xmlValidCtxt vctxt;
10228
10229 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10230 vctxt.valid = 1;
10231 vctxt.error = ctxt->error;
10232 vctxt.warning = ctxt->warning;
10233 vctxt.userData = ctxt->userData;
10234
10235 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10236 ret = -1;
10237 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010238 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10239 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010240
10241 return(ret);
10242}
10243
Daniel Veillardfd573f12003-03-16 17:52:32 +000010244/************************************************************************
10245 * *
10246 * Validation interfaces *
10247 * *
10248 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +000010249/**
10250 * xmlRelaxNGNewValidCtxt:
10251 * @schema: a precompiled XML RelaxNGs
10252 *
10253 * Create an XML RelaxNGs validation context based on the given schema
10254 *
10255 * Returns the validation context or NULL in case of error
10256 */
10257xmlRelaxNGValidCtxtPtr
10258xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
10259 xmlRelaxNGValidCtxtPtr ret;
10260
10261 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10262 if (ret == NULL) {
10263 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +000010264 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010265 return (NULL);
10266 }
10267 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10268 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010269 ret->error = xmlGenericError;
10270 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010271 ret->errNr = 0;
10272 ret->errMax = 0;
10273 ret->err = NULL;
10274 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010275 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010276 ret->states = NULL;
10277 ret->freeState = NULL;
10278 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010279 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010280 return (ret);
10281}
10282
10283/**
10284 * xmlRelaxNGFreeValidCtxt:
10285 * @ctxt: the schema validation context
10286 *
10287 * Free the resources associated to the schema validation context
10288 */
10289void
10290xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010291 int k;
10292
Daniel Veillard6eadf632003-01-23 18:29:16 +000010293 if (ctxt == NULL)
10294 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010295 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +000010296 xmlRelaxNGFreeStates(NULL, ctxt->states);
10297 if (ctxt->freeState != NULL) {
10298 for (k = 0;k < ctxt->freeState->nbState;k++) {
10299 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10300 }
10301 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10302 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010303 if (ctxt->freeStates != NULL) {
10304 for (k = 0;k < ctxt->freeStatesNr;k++) {
10305 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10306 }
10307 xmlFree(ctxt->freeStates);
10308 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010309 if (ctxt->errTab != NULL)
10310 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010311 if (ctxt->elemTab != NULL) {
10312 xmlRegExecCtxtPtr exec;
10313
10314 exec = xmlRelaxNGElemPop(ctxt);
10315 while (exec != NULL) {
10316 xmlRegFreeExecCtxt(exec);
10317 exec = xmlRelaxNGElemPop(ctxt);
10318 }
10319 xmlFree(ctxt->elemTab);
10320 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010321 xmlFree(ctxt);
10322}
10323
10324/**
10325 * xmlRelaxNGSetValidErrors:
10326 * @ctxt: a Relax-NG validation context
10327 * @err: the error function
10328 * @warn: the warning function
10329 * @ctx: the functions context
10330 *
10331 * Set the error and warning callback informations
10332 */
10333void
10334xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10335 xmlRelaxNGValidityErrorFunc err,
10336 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
10337 if (ctxt == NULL)
10338 return;
10339 ctxt->error = err;
10340 ctxt->warning = warn;
10341 ctxt->userData = ctx;
10342}
10343
10344/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010345 * xmlRelaxNGGetValidErrors:
10346 * @ctxt: a Relax-NG validation context
10347 * @err: the error function result
10348 * @warn: the warning function result
10349 * @ctx: the functions context result
10350 *
10351 * Get the error and warning callback informations
10352 *
10353 * Returns -1 in case of error and 0 otherwise
10354 */
10355int
10356xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10357 xmlRelaxNGValidityErrorFunc *err,
10358 xmlRelaxNGValidityWarningFunc *warn, void **ctx) {
10359 if (ctxt == NULL)
10360 return(-1);
10361 if (err != NULL) *err = ctxt->error;
10362 if (warn != NULL) *warn = ctxt->warning;
10363 if (ctx != NULL) *ctx = ctxt->userData;
10364 return(0);
10365}
10366
10367/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010368 * xmlRelaxNGValidateDoc:
10369 * @ctxt: a Relax-NG validation context
10370 * @doc: a parsed document tree
10371 *
10372 * Validate a document tree in memory.
10373 *
10374 * Returns 0 if the document is valid, a positive error code
10375 * number otherwise and -1 in case of internal or API error.
10376 */
10377int
10378xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10379 int ret;
10380
10381 if ((ctxt == NULL) || (doc == NULL))
10382 return(-1);
10383
10384 ctxt->doc = doc;
10385
10386 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010387 /*
10388 * TODO: build error codes
10389 */
10390 if (ret == -1)
10391 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010392 return(ret);
10393}
10394
10395#endif /* LIBXML_SCHEMAS_ENABLED */
10396