blob: 2d266675d110fcb4f7946eb9d4c86e164bd48dde [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 Veillard87254c82006-02-19 15:27:17 +000048#if 0
49#define DEBUG 1
Daniel Veillard4c004142003-10-07 11:33:24 +000050
Daniel Veillard87254c82006-02-19 15:27:17 +000051#define DEBUG_GRAMMAR 1
Daniel Veillard4c004142003-10-07 11:33:24 +000052
Daniel Veillard87254c82006-02-19 15:27:17 +000053#define DEBUG_CONTENT 1
Daniel Veillard4c004142003-10-07 11:33:24 +000054
Daniel Veillard87254c82006-02-19 15:27:17 +000055#define DEBUG_TYPE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000056
Daniel Veillard87254c82006-02-19 15:27:17 +000057#define DEBUG_VALID 1
Daniel Veillard4c004142003-10-07 11:33:24 +000058
Daniel Veillard87254c82006-02-19 15:27:17 +000059#define DEBUG_INTERLEAVE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000060
Daniel Veillard87254c82006-02-19 15:27:17 +000061#define DEBUG_LIST 1
Daniel Veillard4c004142003-10-07 11:33:24 +000062
Daniel Veillard87254c82006-02-19 15:27:17 +000063#define DEBUG_INCLUDE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000064
Daniel Veillard87254c82006-02-19 15:27:17 +000065#define DEBUG_ERROR 1
Daniel Veillard4c004142003-10-07 11:33:24 +000066
Daniel Veillard87254c82006-02-19 15:27:17 +000067#define DEBUG_COMPILE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000068
Daniel Veillard87254c82006-02-19 15:27:17 +000069#define DEBUG_PROGRESSIVE 1
70#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +000071
Daniel Veillard5f1946a2003-03-31 16:38:16 +000072#define MAX_ERROR 5
73
Daniel Veillard6eadf632003-01-23 18:29:16 +000074#define TODO \
75 xmlGenericError(xmlGenericErrorContext, \
76 "Unimplemented block at %s:%d\n", \
77 __FILE__, __LINE__);
78
79typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
80typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
81
82typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
83typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
84
Daniel Veillardd41f4f42003-01-29 21:07:52 +000085typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
86typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
87
Daniel Veillarda9d912d2003-02-01 17:43:10 +000088typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
89typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
90
Daniel Veillard6eadf632003-01-23 18:29:16 +000091typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +000092 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
93 XML_RELAXNG_COMBINE_CHOICE, /* choice */
94 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
Daniel Veillard6eadf632003-01-23 18:29:16 +000095} xmlRelaxNGCombine;
96
Daniel Veillard4c5cf702003-02-21 15:40:34 +000097typedef enum {
98 XML_RELAXNG_CONTENT_ERROR = -1,
99 XML_RELAXNG_CONTENT_EMPTY = 0,
100 XML_RELAXNG_CONTENT_SIMPLE,
101 XML_RELAXNG_CONTENT_COMPLEX
102} xmlRelaxNGContentType;
103
Daniel Veillard6eadf632003-01-23 18:29:16 +0000104typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
105typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
106
107struct _xmlRelaxNGGrammar {
Daniel Veillard4c004142003-10-07 11:33:24 +0000108 xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
109 xmlRelaxNGGrammarPtr children; /* the children grammar if any */
110 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
111 xmlRelaxNGDefinePtr start; /* <start> content */
112 xmlRelaxNGCombine combine; /* the default combine value */
113 xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
114 xmlHashTablePtr defs; /* define* */
115 xmlHashTablePtr refs; /* references */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000116};
117
118
Daniel Veillard6eadf632003-01-23 18:29:16 +0000119typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +0000120 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
121 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000122 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard4c004142003-10-07 11:33:24 +0000123 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
124 XML_RELAXNG_TEXT, /* textual content */
125 XML_RELAXNG_ELEMENT, /* an element */
126 XML_RELAXNG_DATATYPE, /* extenal data type definition */
127 XML_RELAXNG_PARAM, /* extenal data type parameter */
128 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
129 XML_RELAXNG_LIST, /* a list of patterns */
130 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
131 XML_RELAXNG_DEF, /* a definition */
132 XML_RELAXNG_REF, /* reference to a definition */
133 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
134 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
135 XML_RELAXNG_OPTIONAL, /* optional patterns */
136 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
137 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
138 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
139 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
140 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
141 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000142} xmlRelaxNGType;
143
Daniel Veillard52b48c72003-04-13 19:53:42 +0000144#define IS_NULLABLE (1 << 0)
145#define IS_NOT_NULLABLE (1 << 1)
146#define IS_INDETERMINIST (1 << 2)
147#define IS_MIXED (1 << 3)
148#define IS_TRIABLE (1 << 4)
149#define IS_PROCESSED (1 << 5)
150#define IS_COMPILABLE (1 << 6)
151#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000152
Daniel Veillard6eadf632003-01-23 18:29:16 +0000153struct _xmlRelaxNGDefine {
Daniel Veillard4c004142003-10-07 11:33:24 +0000154 xmlRelaxNGType type; /* the type of definition */
155 xmlNodePtr node; /* the node in the source */
156 xmlChar *name; /* the element local name if present */
157 xmlChar *ns; /* the namespace local name if present */
158 xmlChar *value; /* value when available */
159 void *data; /* data lib or specific pointer */
160 xmlRelaxNGDefinePtr content; /* the expected content */
161 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
162 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
163 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
164 xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
165 xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
166 short depth; /* used for the cycle detection */
167 short dflags; /* define related flags */
168 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000169};
170
171/**
172 * _xmlRelaxNG:
173 *
174 * A RelaxNGs definition
175 */
176struct _xmlRelaxNG {
Daniel Veillard4c004142003-10-07 11:33:24 +0000177 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000178 xmlRelaxNGGrammarPtr topgrammar;
179 xmlDocPtr doc;
180
Daniel Veillard4c004142003-10-07 11:33:24 +0000181 int idref; /* requires idref checking */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000182
Daniel Veillard4c004142003-10-07 11:33:24 +0000183 xmlHashTablePtr defs; /* define */
184 xmlHashTablePtr refs; /* references */
185 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
186 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
187 int defNr; /* number of defines used */
188 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000189
Daniel Veillard6eadf632003-01-23 18:29:16 +0000190};
191
Daniel Veillard77648bb2003-02-20 15:03:22 +0000192#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
193#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
194#define XML_RELAXNG_IN_LIST (1 << 2)
195#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
196#define XML_RELAXNG_IN_START (1 << 4)
197#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
198#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
199#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000200#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
201#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000202
203struct _xmlRelaxNGParserCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000204 void *userData; /* user specific data block */
205 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
206 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000207 xmlStructuredErrorFunc serror;
Daniel Veillard42f12e92003-03-07 18:32:59 +0000208 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000209
Daniel Veillard4c004142003-10-07 11:33:24 +0000210 xmlRelaxNGPtr schema; /* The schema in use */
211 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
212 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
213 int flags; /* parser flags */
214 int nbErrors; /* number of errors at parse time */
215 int nbWarnings; /* number of warnings at parse time */
216 const xmlChar *define; /* the current define scope */
217 xmlRelaxNGDefinePtr def; /* the current define */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000218
Daniel Veillard4c004142003-10-07 11:33:24 +0000219 int nbInterleaves;
220 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000221
Daniel Veillard4c004142003-10-07 11:33:24 +0000222 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
223 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
224 xmlChar *URL;
225 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000226
Daniel Veillard4c004142003-10-07 11:33:24 +0000227 int defNr; /* number of defines used */
228 int defMax; /* number of defines aloocated */
229 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard419a7682003-02-03 23:22:49 +0000230
Daniel Veillard4c004142003-10-07 11:33:24 +0000231 const char *buffer;
232 int size;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000233
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000234 /* the document stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000235 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
236 int docNr; /* Depth of the parsing stack */
237 int docMax; /* Max depth of the parsing stack */
238 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000239
240 /* the include stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000241 xmlRelaxNGIncludePtr inc; /* Current parsed include */
242 int incNr; /* Depth of the include parsing stack */
243 int incMax; /* Max depth of the parsing stack */
244 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000245
Daniel Veillard4c004142003-10-07 11:33:24 +0000246 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000247
248 /* used to compile content models */
Daniel Veillard4c004142003-10-07 11:33:24 +0000249 xmlAutomataPtr am; /* the automata */
250 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard03c2f0a2004-01-25 19:54:59 +0000251
252 int crng; /* compact syntax and other flags */
Daniel Veillard42595322004-11-08 10:52:06 +0000253 int freedoc; /* need to free the document */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000254};
255
256#define FLAGS_IGNORABLE 1
257#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000258#define FLAGS_MIXED_CONTENT 4
Daniel Veillardb30ca312005-09-04 13:50:03 +0000259#define FLAGS_NOERROR 8
Daniel Veillard6eadf632003-01-23 18:29:16 +0000260
261/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000262 * xmlRelaxNGInterleaveGroup:
263 *
264 * A RelaxNGs partition set associated to lists of definitions
265 */
266typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
267typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
268struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000269 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
270 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
271 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000272};
273
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000274#define IS_DETERMINIST 1
275#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000276
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000277/**
278 * xmlRelaxNGPartitions:
279 *
280 * A RelaxNGs partition associated to an interleave group
281 */
282typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
283typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
284struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000285 int nbgroups; /* number of groups in the partitions */
286 xmlHashTablePtr triage; /* hash table used to direct nodes to the
287 * right group when possible */
288 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000289 xmlRelaxNGInterleaveGroupPtr *groups;
290};
291
292/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000293 * xmlRelaxNGValidState:
294 *
295 * A RelaxNGs validation state
296 */
297#define MAX_ATTR 20
298typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
299typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
300struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000301 xmlNodePtr node; /* the current node */
302 xmlNodePtr seq; /* the sequence of children left to validate */
303 int nbAttrs; /* the number of attributes */
304 int maxAttrs; /* the size of attrs */
305 int nbAttrLeft; /* the number of attributes left to validate */
306 xmlChar *value; /* the value when operating on string */
307 xmlChar *endvalue; /* the end value when operating on string */
308 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000309};
310
311/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000312 * xmlRelaxNGStates:
313 *
314 * A RelaxNGs container for validation state
315 */
316typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
317typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
318struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000319 int nbState; /* the number of states */
320 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000321 xmlRelaxNGValidStatePtr *tabState;
322};
323
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000324#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000325
Daniel Veillardfd573f12003-03-16 17:52:32 +0000326/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000327 * xmlRelaxNGValidError:
328 *
329 * A RelaxNGs validation error
330 */
331typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
332typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
333struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000334 xmlRelaxNGValidErr err; /* the error number */
335 int flags; /* flags */
336 xmlNodePtr node; /* the current node */
337 xmlNodePtr seq; /* the current child */
338 const xmlChar *arg1; /* first arg */
339 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000340};
341
342/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000343 * xmlRelaxNGValidCtxt:
344 *
345 * A RelaxNGs validation context
346 */
347
348struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000349 void *userData; /* user specific data block */
350 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
351 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000352 xmlStructuredErrorFunc serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000353 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000354
Daniel Veillard4c004142003-10-07 11:33:24 +0000355 xmlRelaxNGPtr schema; /* The schema in use */
356 xmlDocPtr doc; /* the document being validated */
357 int flags; /* validation flags */
358 int depth; /* validation depth */
359 int idref; /* requires idref checking */
360 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000361
362 /*
363 * Errors accumulated in branches may have to be stacked to be
364 * provided back when it's sure they affect validation.
365 */
366 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000367 int errNr; /* Depth of the error stack */
368 int errMax; /* Max depth of the error stack */
369 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000370
Daniel Veillard4c004142003-10-07 11:33:24 +0000371 xmlRelaxNGValidStatePtr state; /* the current validation state */
372 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000373
Daniel Veillard4c004142003-10-07 11:33:24 +0000374 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
375 int freeStatesNr;
376 int freeStatesMax;
377 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000378
379 /*
380 * This is used for "progressive" validation
381 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000382 xmlRegExecCtxtPtr elem; /* the current element regexp */
383 int elemNr; /* the number of element validated */
384 int elemMax; /* the max depth of elements */
385 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
386 int pstate; /* progressive state */
387 xmlNodePtr pnode; /* the current node */
388 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
389 int perr; /* signal error in content model
390 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000391};
392
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000393/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000394 * xmlRelaxNGInclude:
395 *
396 * Structure associated to a RelaxNGs document element
397 */
398struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000399 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
400 xmlChar *href; /* the normalized href value */
401 xmlDocPtr doc; /* the associated XML document */
402 xmlRelaxNGDefinePtr content; /* the definitions */
403 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000404};
405
406/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000407 * xmlRelaxNGDocument:
408 *
409 * Structure associated to a RelaxNGs document element
410 */
411struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000412 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000413 xmlChar *href; /* the normalized href value */
414 xmlDocPtr doc; /* the associated XML document */
415 xmlRelaxNGDefinePtr content; /* the definitions */
416 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000417};
418
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000419
Daniel Veillard6eadf632003-01-23 18:29:16 +0000420/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000421 * *
422 * Some factorized error routines *
423 * *
424 ************************************************************************/
425
426/**
427 * xmlRngPErrMemory:
428 * @ctxt: an Relax-NG parser context
429 * @extra: extra informations
430 *
431 * Handle a redefinition of attribute error
432 */
433static void
434xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
435{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000436 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000437 xmlGenericErrorFunc channel = NULL;
438 void *data = NULL;
439
440 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000441 if (ctxt->serror != NULL)
442 schannel = ctxt->serror;
443 else
444 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000445 data = ctxt->userData;
446 ctxt->nbErrors++;
447 }
448 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000449 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000450 NULL, NULL, XML_FROM_RELAXNGP,
451 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
452 NULL, NULL, 0, 0,
453 "Memory allocation failed : %s\n", extra);
454 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000455 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000456 NULL, NULL, XML_FROM_RELAXNGP,
457 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
458 NULL, NULL, 0, 0, "Memory allocation failed\n");
459}
460
461/**
462 * xmlRngVErrMemory:
463 * @ctxt: a Relax-NG validation context
464 * @extra: extra informations
465 *
466 * Handle a redefinition of attribute error
467 */
468static void
469xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
470{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000471 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000472 xmlGenericErrorFunc channel = NULL;
473 void *data = NULL;
474
475 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000476 if (ctxt->serror != NULL)
477 schannel = ctxt->serror;
478 else
479 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000480 data = ctxt->userData;
481 ctxt->nbErrors++;
482 }
483 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000484 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000485 NULL, NULL, XML_FROM_RELAXNGV,
486 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
487 NULL, NULL, 0, 0,
488 "Memory allocation failed : %s\n", extra);
489 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000490 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000491 NULL, NULL, XML_FROM_RELAXNGV,
492 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
493 NULL, NULL, 0, 0, "Memory allocation failed\n");
494}
495
496/**
497 * xmlRngPErr:
498 * @ctxt: a Relax-NG parser context
499 * @node: the node raising the error
500 * @error: the error code
501 * @msg: message
502 * @str1: extra info
503 * @str2: extra info
504 *
505 * Handle a Relax NG Parsing error
506 */
507static void
508xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
509 const char *msg, const xmlChar * str1, const xmlChar * str2)
510{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000511 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000512 xmlGenericErrorFunc channel = NULL;
513 void *data = NULL;
514
515 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000516 if (ctxt->serror != NULL)
517 schannel = ctxt->serror;
518 else
519 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000520 data = ctxt->userData;
521 ctxt->nbErrors++;
522 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000523 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000524 NULL, node, XML_FROM_RELAXNGP,
525 error, XML_ERR_ERROR, NULL, 0,
526 (const char *) str1, (const char *) str2, NULL, 0, 0,
527 msg, str1, str2);
528}
529
530/**
531 * xmlRngVErr:
532 * @ctxt: a Relax-NG validation context
533 * @node: the node raising the error
534 * @error: the error code
535 * @msg: message
536 * @str1: extra info
537 * @str2: extra info
538 *
539 * Handle a Relax NG Validation error
540 */
541static void
542xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
543 const char *msg, const xmlChar * str1, const xmlChar * str2)
544{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000545 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000546 xmlGenericErrorFunc channel = NULL;
547 void *data = NULL;
548
549 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000550 if (ctxt->serror != NULL)
551 schannel = ctxt->serror;
552 else
553 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000554 data = ctxt->userData;
555 ctxt->nbErrors++;
556 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000557 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000558 NULL, node, XML_FROM_RELAXNGV,
559 error, XML_ERR_ERROR, NULL, 0,
560 (const char *) str1, (const char *) str2, NULL, 0, 0,
561 msg, str1, str2);
562}
563
564/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000565 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000566 * Preliminary type checking interfaces *
567 * *
568 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000569
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000570/**
571 * xmlRelaxNGTypeHave:
572 * @data: data needed for the library
573 * @type: the type name
574 * @value: the value to check
575 *
576 * Function provided by a type library to check if a type is exported
577 *
578 * Returns 1 if yes, 0 if no and -1 in case of error.
579 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000580typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000581
582/**
583 * xmlRelaxNGTypeCheck:
584 * @data: data needed for the library
585 * @type: the type name
586 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000587 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000588 *
589 * Function provided by a type library to check if a value match a type
590 *
591 * Returns 1 if yes, 0 if no and -1 in case of error.
592 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000593typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
594 const xmlChar * value, void **result,
595 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000596
597/**
598 * xmlRelaxNGFacetCheck:
599 * @data: data needed for the library
600 * @type: the type name
601 * @facet: the facet name
602 * @val: the facet value
603 * @strval: the string value
604 * @value: the value to check
605 *
606 * Function provided by a type library to check a value facet
607 *
608 * Returns 1 if yes, 0 if no and -1 in case of error.
609 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000610typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
611 const xmlChar * facet,
612 const xmlChar * val,
613 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000614
615/**
616 * xmlRelaxNGTypeFree:
617 * @data: data needed for the library
618 * @result: the value to free
619 *
620 * Function provided by a type library to free a returned result
621 */
622typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000623
624/**
625 * xmlRelaxNGTypeCompare:
626 * @data: data needed for the library
627 * @type: the type name
628 * @value1: the first value
629 * @value2: the second value
630 *
631 * Function provided by a type library to compare two values accordingly
632 * to a type.
633 *
634 * Returns 1 if yes, 0 if no and -1 in case of error.
635 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000636typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
637 const xmlChar * value1,
638 xmlNodePtr ctxt1,
639 void *comp1,
640 const xmlChar * value2,
641 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000642typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
643typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
644struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000645 const xmlChar *namespace; /* the datatypeLibrary value */
646 void *data; /* data needed for the library */
647 xmlRelaxNGTypeHave have; /* the export function */
648 xmlRelaxNGTypeCheck check; /* the checking function */
649 xmlRelaxNGTypeCompare comp; /* the compare function */
650 xmlRelaxNGFacetCheck facet; /* the facet check function */
651 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000652};
653
654/************************************************************************
655 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000656 * Allocation functions *
657 * *
658 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000659static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
660static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000661static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000662static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000663static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
664 ATTRIBUTE_UNUSED,
665 xmlRelaxNGValidStatePtr state1,
666 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000667static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000668 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000669
670/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000671 * xmlRelaxNGFreeDocument:
672 * @docu: a document structure
673 *
674 * Deallocate a RelaxNG document structure.
675 */
676static void
677xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
678{
679 if (docu == NULL)
680 return;
681
682 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000683 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000684 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000685 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000686 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000687 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000688 xmlFree(docu);
689}
690
691/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000692 * xmlRelaxNGFreeDocumentList:
693 * @docu: a list of document structure
694 *
695 * Deallocate a RelaxNG document structures.
696 */
697static void
698xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
699{
700 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000701
Daniel Veillardc482e262003-02-26 14:48:48 +0000702 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000703 next = docu->next;
704 xmlRelaxNGFreeDocument(docu);
705 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000706 }
707}
708
709/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000710 * xmlRelaxNGFreeInclude:
711 * @incl: a include structure
712 *
713 * Deallocate a RelaxNG include structure.
714 */
715static void
716xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
717{
718 if (incl == NULL)
719 return;
720
721 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000722 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000723 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000724 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000725 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000726 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000727 xmlFree(incl);
728}
729
730/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000731 * xmlRelaxNGFreeIncludeList:
732 * @incl: a include structure list
733 *
734 * Deallocate a RelaxNG include structure.
735 */
736static void
737xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
738{
739 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000740
Daniel Veillardc482e262003-02-26 14:48:48 +0000741 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000742 next = incl->next;
743 xmlRelaxNGFreeInclude(incl);
744 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000745 }
746}
747
748/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000749 * xmlRelaxNGNewRelaxNG:
750 * @ctxt: a Relax-NG validation context (optional)
751 *
752 * Allocate a new RelaxNG structure.
753 *
754 * Returns the newly allocated structure or NULL in case or error
755 */
756static xmlRelaxNGPtr
757xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
758{
759 xmlRelaxNGPtr ret;
760
761 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
762 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000763 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000764 return (NULL);
765 }
766 memset(ret, 0, sizeof(xmlRelaxNG));
767
768 return (ret);
769}
770
771/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000772 * xmlRelaxNGFreeInnerSchema:
773 * @schema: a schema structure
774 *
775 * Deallocate a RelaxNG schema structure.
776 */
777static void
778xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
779{
780 if (schema == NULL)
781 return;
782
783 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000784 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000785 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000786 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000787
Daniel Veillard4c004142003-10-07 11:33:24 +0000788 for (i = 0; i < schema->defNr; i++)
789 xmlRelaxNGFreeDefine(schema->defTab[i]);
790 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000791 }
792
793 xmlFree(schema);
794}
795
796/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000797 * xmlRelaxNGFree:
798 * @schema: a schema structure
799 *
800 * Deallocate a RelaxNG structure.
801 */
802void
803xmlRelaxNGFree(xmlRelaxNGPtr schema)
804{
805 if (schema == NULL)
806 return;
807
Daniel Veillard6eadf632003-01-23 18:29:16 +0000808 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000809 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000810 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000811 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000812 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000813 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000814 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000815 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000816 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000817 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000818
Daniel Veillard4c004142003-10-07 11:33:24 +0000819 for (i = 0; i < schema->defNr; i++)
820 xmlRelaxNGFreeDefine(schema->defTab[i]);
821 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000822 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000823
824 xmlFree(schema);
825}
826
827/**
828 * xmlRelaxNGNewGrammar:
829 * @ctxt: a Relax-NG validation context (optional)
830 *
831 * Allocate a new RelaxNG grammar.
832 *
833 * Returns the newly allocated structure or NULL in case or error
834 */
835static xmlRelaxNGGrammarPtr
836xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
837{
838 xmlRelaxNGGrammarPtr ret;
839
840 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
841 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000842 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000843 return (NULL);
844 }
845 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
846
847 return (ret);
848}
849
850/**
851 * xmlRelaxNGFreeGrammar:
852 * @grammar: a grammar structure
853 *
854 * Deallocate a RelaxNG grammar structure.
855 */
856static void
857xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
858{
859 if (grammar == NULL)
860 return;
861
Daniel Veillardc482e262003-02-26 14:48:48 +0000862 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000863 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000864 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000865 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000866 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000867 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000868 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000869 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000870 }
871 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000872 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000873 }
874
875 xmlFree(grammar);
876}
877
878/**
879 * xmlRelaxNGNewDefine:
880 * @ctxt: a Relax-NG validation context
881 * @node: the node in the input document.
882 *
883 * Allocate a new RelaxNG define.
884 *
885 * Returns the newly allocated structure or NULL in case or error
886 */
887static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000888xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000889{
890 xmlRelaxNGDefinePtr ret;
891
Daniel Veillard419a7682003-02-03 23:22:49 +0000892 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000893 ctxt->defMax = 16;
894 ctxt->defNr = 0;
895 ctxt->defTab = (xmlRelaxNGDefinePtr *)
896 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
897 if (ctxt->defTab == NULL) {
898 xmlRngPErrMemory(ctxt, "allocating define\n");
899 return (NULL);
900 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000901 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000902 xmlRelaxNGDefinePtr *tmp;
903
904 ctxt->defMax *= 2;
905 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
906 ctxt->defMax *
907 sizeof
908 (xmlRelaxNGDefinePtr));
909 if (tmp == NULL) {
910 xmlRngPErrMemory(ctxt, "allocating define\n");
911 return (NULL);
912 }
913 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000914 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000915 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
916 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000917 xmlRngPErrMemory(ctxt, "allocating define\n");
918 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000919 }
920 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000921 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000922 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000923 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000924 return (ret);
925}
926
927/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000928 * xmlRelaxNGFreePartition:
929 * @partitions: a partition set structure
930 *
931 * Deallocate RelaxNG partition set structures.
932 */
933static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000934xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
935{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000936 xmlRelaxNGInterleaveGroupPtr group;
937 int j;
938
939 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000940 if (partitions->groups != NULL) {
941 for (j = 0; j < partitions->nbgroups; j++) {
942 group = partitions->groups[j];
943 if (group != NULL) {
944 if (group->defs != NULL)
945 xmlFree(group->defs);
946 if (group->attrs != NULL)
947 xmlFree(group->attrs);
948 xmlFree(group);
949 }
950 }
951 xmlFree(partitions->groups);
952 }
953 if (partitions->triage != NULL) {
954 xmlHashFree(partitions->triage, NULL);
955 }
956 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000957 }
958}
Daniel Veillard4c004142003-10-07 11:33:24 +0000959
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000960/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000961 * xmlRelaxNGFreeDefine:
962 * @define: a define structure
963 *
964 * Deallocate a RelaxNG define structure.
965 */
966static void
967xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
968{
969 if (define == NULL)
970 return;
971
Daniel Veillard4c004142003-10-07 11:33:24 +0000972 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
973 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000974
Daniel Veillard4c004142003-10-07 11:33:24 +0000975 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
976 if ((lib != NULL) && (lib->freef != NULL))
977 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000978 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000979 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
980 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
981 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
982 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000983 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000984 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000985 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000986 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000987 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000988 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000989 if (define->contModel != NULL)
990 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000991 xmlFree(define);
992}
993
994/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000995 * xmlRelaxNGNewStates:
996 * @ctxt: a Relax-NG validation context
997 * @size: the default size for the container
998 *
999 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001000 *
1001 * Returns the newly allocated structure or NULL in case or error
1002 */
1003static xmlRelaxNGStatesPtr
1004xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
1005{
1006 xmlRelaxNGStatesPtr ret;
1007
Daniel Veillard798024a2003-03-19 10:36:09 +00001008 if ((ctxt != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001009 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
1010 ctxt->freeStatesNr--;
1011 ret = ctxt->freeStates[ctxt->freeStatesNr];
1012 ret->nbState = 0;
1013 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +00001014 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001015 if (size < 16)
1016 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001017
1018 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +00001019 (size -
1020 1) *
1021 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001022 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001023 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001024 return (NULL);
1025 }
1026 ret->nbState = 0;
1027 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001028 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1029 sizeof
1030 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001031 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001032 xmlRngVErrMemory(ctxt, "allocating states\n");
1033 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001034 return (NULL);
1035 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001036 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001037}
1038
1039/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001040 * xmlRelaxNGAddStateUniq:
1041 * @ctxt: a Relax-NG validation context
1042 * @states: the states container
1043 * @state: the validation state
1044 *
1045 * Add a RelaxNG validation state to the container without checking
1046 * for unicity.
1047 *
1048 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1049 */
1050static int
1051xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001052 xmlRelaxNGStatesPtr states,
1053 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001054{
1055 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001056 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001057 }
1058 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001059 xmlRelaxNGValidStatePtr *tmp;
1060 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001061
Daniel Veillard4c004142003-10-07 11:33:24 +00001062 size = states->maxState * 2;
1063 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1064 (size) *
1065 sizeof
1066 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001067 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001068 xmlRngVErrMemory(ctxt, "adding states\n");
1069 return (-1);
1070 }
1071 states->tabState = tmp;
1072 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001073 }
1074 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001075 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001076}
1077
1078/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001079 * xmlRelaxNGAddState:
1080 * @ctxt: a Relax-NG validation context
1081 * @states: the states container
1082 * @state: the validation state
1083 *
1084 * Add a RelaxNG validation state to the container
1085 *
1086 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1087 */
1088static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001089xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1090 xmlRelaxNGStatesPtr states,
1091 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001092{
1093 int i;
1094
1095 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001096 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001097 }
1098 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001099 xmlRelaxNGValidStatePtr *tmp;
1100 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001101
Daniel Veillard4c004142003-10-07 11:33:24 +00001102 size = states->maxState * 2;
1103 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1104 (size) *
1105 sizeof
1106 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001107 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001108 xmlRngVErrMemory(ctxt, "adding states\n");
1109 return (-1);
1110 }
1111 states->tabState = tmp;
1112 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001113 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001114 for (i = 0; i < states->nbState; i++) {
1115 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1116 xmlRelaxNGFreeValidState(ctxt, state);
1117 return (0);
1118 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001119 }
1120 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001121 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001122}
1123
1124/**
1125 * xmlRelaxNGFreeStates:
1126 * @ctxt: a Relax-NG validation context
1127 * @states: teh container
1128 *
1129 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001130 */
1131static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001132xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001133 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001134{
Daniel Veillard798024a2003-03-19 10:36:09 +00001135 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001136 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001137 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001138 ctxt->freeStatesMax = 40;
1139 ctxt->freeStatesNr = 0;
1140 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1141 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1142 if (ctxt->freeStates == NULL) {
1143 xmlRngVErrMemory(ctxt, "storing states\n");
1144 }
1145 } else if ((ctxt != NULL)
1146 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1147 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001148
Daniel Veillard4c004142003-10-07 11:33:24 +00001149 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1150 2 * ctxt->freeStatesMax *
1151 sizeof
1152 (xmlRelaxNGStatesPtr));
1153 if (tmp == NULL) {
1154 xmlRngVErrMemory(ctxt, "storing states\n");
1155 xmlFree(states->tabState);
1156 xmlFree(states);
1157 return;
1158 }
1159 ctxt->freeStates = tmp;
1160 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001161 }
1162 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001163 xmlFree(states->tabState);
1164 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001165 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001166 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001167 }
1168}
1169
1170/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001171 * xmlRelaxNGNewValidState:
1172 * @ctxt: a Relax-NG validation context
1173 * @node: the current node or NULL for the document
1174 *
1175 * Allocate a new RelaxNG validation state
1176 *
1177 * Returns the newly allocated structure or NULL in case or error
1178 */
1179static xmlRelaxNGValidStatePtr
1180xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1181{
1182 xmlRelaxNGValidStatePtr ret;
1183 xmlAttrPtr attr;
1184 xmlAttrPtr attrs[MAX_ATTR];
1185 int nbAttrs = 0;
1186 xmlNodePtr root = NULL;
1187
1188 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001189 root = xmlDocGetRootElement(ctxt->doc);
1190 if (root == NULL)
1191 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001192 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001193 attr = node->properties;
1194 while (attr != NULL) {
1195 if (nbAttrs < MAX_ATTR)
1196 attrs[nbAttrs++] = attr;
1197 else
1198 nbAttrs++;
1199 attr = attr->next;
1200 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001201 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001202 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1203 ctxt->freeState->nbState--;
1204 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001205 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001206 ret =
1207 (xmlRelaxNGValidStatePtr)
1208 xmlMalloc(sizeof(xmlRelaxNGValidState));
1209 if (ret == NULL) {
1210 xmlRngVErrMemory(ctxt, "allocating states\n");
1211 return (NULL);
1212 }
1213 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001214 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001215 ret->value = NULL;
1216 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001217 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001218 ret->node = (xmlNodePtr) ctxt->doc;
1219 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001220 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001221 ret->node = node;
1222 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001223 }
1224 ret->nbAttrs = 0;
1225 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001226 if (ret->attrs == NULL) {
1227 if (nbAttrs < 4)
1228 ret->maxAttrs = 4;
1229 else
1230 ret->maxAttrs = nbAttrs;
1231 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1232 sizeof(xmlAttrPtr));
1233 if (ret->attrs == NULL) {
1234 xmlRngVErrMemory(ctxt, "allocating states\n");
1235 return (ret);
1236 }
1237 } else if (ret->maxAttrs < nbAttrs) {
1238 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001239
Daniel Veillard4c004142003-10-07 11:33:24 +00001240 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1241 sizeof(xmlAttrPtr));
1242 if (tmp == NULL) {
1243 xmlRngVErrMemory(ctxt, "allocating states\n");
1244 return (ret);
1245 }
1246 ret->attrs = tmp;
1247 ret->maxAttrs = nbAttrs;
1248 }
1249 ret->nbAttrs = nbAttrs;
1250 if (nbAttrs < MAX_ATTR) {
1251 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1252 } else {
1253 attr = node->properties;
1254 nbAttrs = 0;
1255 while (attr != NULL) {
1256 ret->attrs[nbAttrs++] = attr;
1257 attr = attr->next;
1258 }
1259 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001260 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001261 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001262 return (ret);
1263}
1264
1265/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001266 * xmlRelaxNGCopyValidState:
1267 * @ctxt: a Relax-NG validation context
1268 * @state: a validation state
1269 *
1270 * Copy the validation state
1271 *
1272 * Returns the newly allocated structure or NULL in case or error
1273 */
1274static xmlRelaxNGValidStatePtr
1275xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001276 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001277{
1278 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001279 unsigned int maxAttrs;
1280 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001281
1282 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001283 return (NULL);
1284 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1285 ctxt->freeState->nbState--;
1286 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001287 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001288 ret =
1289 (xmlRelaxNGValidStatePtr)
1290 xmlMalloc(sizeof(xmlRelaxNGValidState));
1291 if (ret == NULL) {
1292 xmlRngVErrMemory(ctxt, "allocating states\n");
1293 return (NULL);
1294 }
1295 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001296 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001297 attrs = ret->attrs;
1298 maxAttrs = ret->maxAttrs;
1299 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1300 ret->attrs = attrs;
1301 ret->maxAttrs = maxAttrs;
1302 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001303 if (ret->attrs == NULL) {
1304 ret->maxAttrs = state->maxAttrs;
1305 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1306 sizeof(xmlAttrPtr));
1307 if (ret->attrs == NULL) {
1308 xmlRngVErrMemory(ctxt, "allocating states\n");
1309 ret->nbAttrs = 0;
1310 return (ret);
1311 }
1312 } else if (ret->maxAttrs < state->nbAttrs) {
1313 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001314
Daniel Veillard4c004142003-10-07 11:33:24 +00001315 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1316 sizeof(xmlAttrPtr));
1317 if (tmp == NULL) {
1318 xmlRngVErrMemory(ctxt, "allocating states\n");
1319 ret->nbAttrs = 0;
1320 return (ret);
1321 }
1322 ret->maxAttrs = state->maxAttrs;
1323 ret->attrs = tmp;
1324 }
1325 memcpy(ret->attrs, state->attrs,
1326 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001327 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001328 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001329}
1330
1331/**
1332 * xmlRelaxNGEqualValidState:
1333 * @ctxt: a Relax-NG validation context
1334 * @state1: a validation state
1335 * @state2: a validation state
1336 *
1337 * Compare the validation states for equality
1338 *
1339 * Returns 1 if equald, 0 otherwise
1340 */
1341static int
1342xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001343 xmlRelaxNGValidStatePtr state1,
1344 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001345{
1346 int i;
1347
1348 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001349 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001350 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001351 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001352 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001353 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001354 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001355 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001356 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001357 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001358 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001359 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001360 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001361 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001362 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001363 (!xmlStrEqual(state1->value, state2->value)))
1364 return (0);
1365 for (i = 0; i < state1->nbAttrs; i++) {
1366 if (state1->attrs[i] != state2->attrs[i])
1367 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001368 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001369 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001370}
1371
1372/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001373 * xmlRelaxNGFreeValidState:
1374 * @state: a validation state structure
1375 *
1376 * Deallocate a RelaxNG validation state structure.
1377 */
1378static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001379xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001380 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001381{
1382 if (state == NULL)
1383 return;
1384
Daniel Veillard798024a2003-03-19 10:36:09 +00001385 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001386 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001387 }
1388 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001389 if (state->attrs != NULL)
1390 xmlFree(state->attrs);
1391 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001392 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001393 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001394 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001395}
1396
1397/************************************************************************
1398 * *
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001399 * Semi internal functions *
1400 * *
1401 ************************************************************************/
1402
1403/**
1404 * xmlRelaxParserSetFlag:
1405 * @ctxt: a RelaxNG parser context
1406 * @flags: a set of flags values
1407 *
1408 * Semi private function used to pass informations to a parser context
1409 * which are a combination of xmlRelaxNGParserFlag .
1410 *
1411 * Returns 0 if success and -1 in case of error
1412 */
1413int
1414xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1415{
1416 if (ctxt == NULL) return(-1);
1417 if (flags & XML_RELAXNGP_FREE_DOC) {
1418 ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1419 flags -= XML_RELAXNGP_FREE_DOC;
1420 }
1421 if (flags & XML_RELAXNGP_CRNG) {
1422 ctxt->crng |= XML_RELAXNGP_CRNG;
1423 flags -= XML_RELAXNGP_CRNG;
1424 }
1425 if (flags != 0) return(-1);
1426 return(0);
1427}
1428
1429/************************************************************************
1430 * *
1431 * Document functions *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001432 * *
1433 ************************************************************************/
1434static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001435 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001436
1437/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001438 * xmlRelaxNGIncludePush:
1439 * @ctxt: the parser context
1440 * @value: the element doc
1441 *
1442 * Pushes a new include on top of the include stack
1443 *
1444 * Returns 0 in case of error, the index in the stack otherwise
1445 */
1446static int
1447xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001448 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001449{
1450 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001451 ctxt->incMax = 4;
1452 ctxt->incNr = 0;
1453 ctxt->incTab =
1454 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1455 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001456 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001457 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001458 return (0);
1459 }
1460 }
1461 if (ctxt->incNr >= ctxt->incMax) {
1462 ctxt->incMax *= 2;
1463 ctxt->incTab =
1464 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001465 ctxt->incMax *
1466 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001467 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001468 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001469 return (0);
1470 }
1471 }
1472 ctxt->incTab[ctxt->incNr] = value;
1473 ctxt->inc = value;
1474 return (ctxt->incNr++);
1475}
1476
1477/**
1478 * xmlRelaxNGIncludePop:
1479 * @ctxt: the parser context
1480 *
1481 * Pops the top include from the include stack
1482 *
1483 * Returns the include just removed
1484 */
1485static xmlRelaxNGIncludePtr
1486xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1487{
1488 xmlRelaxNGIncludePtr ret;
1489
1490 if (ctxt->incNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +00001491 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001492 ctxt->incNr--;
1493 if (ctxt->incNr > 0)
1494 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1495 else
1496 ctxt->inc = NULL;
1497 ret = ctxt->incTab[ctxt->incNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001498 ctxt->incTab[ctxt->incNr] = NULL;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001499 return (ret);
1500}
1501
1502/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001503 * xmlRelaxNGRemoveRedefine:
1504 * @ctxt: the parser context
1505 * @URL: the normalized URL
1506 * @target: the included target
1507 * @name: the define name to eliminate
1508 *
1509 * Applies the elimination algorithm of 4.7
1510 *
1511 * Returns 0 in case of error, 1 in case of success.
1512 */
1513static int
1514xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001515 const xmlChar * URL ATTRIBUTE_UNUSED,
1516 xmlNodePtr target, const xmlChar * name)
1517{
Daniel Veillard5add8682003-03-10 13:13:58 +00001518 int found = 0;
1519 xmlNodePtr tmp, tmp2;
1520 xmlChar *name2;
1521
1522#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001523 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001524 xmlGenericError(xmlGenericErrorContext,
1525 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001526 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001527 xmlGenericError(xmlGenericErrorContext,
1528 "Elimination of <include> define %s from %s\n",
1529 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001530#endif
1531 tmp = target;
1532 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001533 tmp2 = tmp->next;
1534 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1535 found = 1;
1536 xmlUnlinkNode(tmp);
1537 xmlFreeNode(tmp);
1538 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1539 name2 = xmlGetProp(tmp, BAD_CAST "name");
1540 xmlRelaxNGNormExtSpace(name2);
1541 if (name2 != NULL) {
1542 if (xmlStrEqual(name, name2)) {
1543 found = 1;
1544 xmlUnlinkNode(tmp);
1545 xmlFreeNode(tmp);
1546 }
1547 xmlFree(name2);
1548 }
1549 } else if (IS_RELAXNG(tmp, "include")) {
1550 xmlChar *href = NULL;
Daniel Veillard807daf82004-02-22 22:13:27 +00001551 xmlRelaxNGDocumentPtr inc = tmp->psvi;
Daniel Veillard5add8682003-03-10 13:13:58 +00001552
Daniel Veillard4c004142003-10-07 11:33:24 +00001553 if ((inc != NULL) && (inc->doc != NULL) &&
1554 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001555
Daniel Veillard4c004142003-10-07 11:33:24 +00001556 if (xmlStrEqual
1557 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001558#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001559 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001560#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001561 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1562 inc->doc->children->
1563 children, name) == 1) {
1564 found = 1;
1565 }
1566 if (href != NULL)
1567 xmlFree(href);
1568 }
1569 }
1570 }
1571 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001572 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001573 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001574}
1575
1576/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001577 * xmlRelaxNGLoadInclude:
1578 * @ctxt: the parser context
1579 * @URL: the normalized URL
1580 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001581 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001582 *
1583 * First lookup if the document is already loaded into the parser context,
1584 * check against recursion. If not found the resource is loaded and
1585 * the content is preprocessed before being returned back to the caller.
1586 *
1587 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1588 */
1589static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001590xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1591 xmlNodePtr node, const xmlChar * ns)
1592{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001593 xmlRelaxNGIncludePtr ret = NULL;
1594 xmlDocPtr doc;
1595 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001596 xmlNodePtr root, cur;
1597
1598#ifdef DEBUG_INCLUDE
1599 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001600 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001601#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001602
1603 /*
1604 * check against recursion in the stack
1605 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001606 for (i = 0; i < ctxt->incNr; i++) {
1607 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1608 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1609 "Detected an Include recursion for %s\n", URL,
1610 NULL);
1611 return (NULL);
1612 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001613 }
1614
1615 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001616 * load the document
1617 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001618 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001619 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001620 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1621 "xmlRelaxNG: could not load %s\n", URL, NULL);
1622 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001623 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001624#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001625 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001626#endif
1627
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001628 /*
1629 * Allocate the document structures and register it first.
1630 */
1631 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1632 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001633 xmlRngPErrMemory(ctxt, "allocating include\n");
1634 xmlFreeDoc(doc);
1635 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001636 }
1637 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1638 ret->doc = doc;
1639 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001640 ret->next = ctxt->includes;
1641 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001642
1643 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001644 * transmit the ns if needed
1645 */
1646 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001647 root = xmlDocGetRootElement(doc);
1648 if (root != NULL) {
1649 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1650 xmlSetProp(root, BAD_CAST "ns", ns);
1651 }
1652 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001653 }
1654
1655 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001656 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001657 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001658 xmlRelaxNGIncludePush(ctxt, ret);
1659
1660 /*
1661 * Some preprocessing of the document content, this include recursing
1662 * in the include stack.
1663 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001664#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001665 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001666#endif
1667
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001668 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1669 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001670 ctxt->inc = NULL;
1671 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001672 }
1673
1674 /*
1675 * Pop up the include from the stack
1676 */
1677 xmlRelaxNGIncludePop(ctxt);
1678
Daniel Veillard5add8682003-03-10 13:13:58 +00001679#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001680 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001681#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001682 /*
1683 * Check that the top element is a grammar
1684 */
1685 root = xmlDocGetRootElement(doc);
1686 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001687 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1688 "xmlRelaxNG: included document is empty %s\n", URL,
1689 NULL);
1690 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001691 }
1692 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001693 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1694 "xmlRelaxNG: included document %s root is not a grammar\n",
1695 URL, NULL);
1696 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001697 }
1698
1699 /*
1700 * Elimination of redefined rules in the include.
1701 */
1702 cur = node->children;
1703 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001704 if (IS_RELAXNG(cur, "start")) {
1705 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001706
Daniel Veillard4c004142003-10-07 11:33:24 +00001707 found =
1708 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1709 if (!found) {
1710 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1711 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1712 URL, NULL);
1713 }
1714 } else if (IS_RELAXNG(cur, "define")) {
1715 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001716
Daniel Veillard4c004142003-10-07 11:33:24 +00001717 name = xmlGetProp(cur, BAD_CAST "name");
1718 if (name == NULL) {
1719 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1720 "xmlRelaxNG: include %s has define without name\n",
1721 URL, NULL);
1722 } else {
1723 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001724
Daniel Veillard4c004142003-10-07 11:33:24 +00001725 xmlRelaxNGNormExtSpace(name);
1726 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1727 root->children, name);
1728 if (!found) {
1729 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1730 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1731 URL, name);
1732 }
1733 xmlFree(name);
1734 }
1735 }
1736 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001737 }
1738
1739
Daniel Veillard4c004142003-10-07 11:33:24 +00001740 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001741}
1742
1743/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001744 * xmlRelaxNGValidErrorPush:
1745 * @ctxt: the validation context
1746 * @err: the error code
1747 * @arg1: the first string argument
1748 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001749 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001750 *
1751 * Pushes a new error on top of the error stack
1752 *
1753 * Returns 0 in case of error, the index in the stack otherwise
1754 */
1755static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001756xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1757 xmlRelaxNGValidErr err, const xmlChar * arg1,
1758 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001759{
1760 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001761
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001762#ifdef DEBUG_ERROR
1763 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001764 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001765#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001766 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001767 ctxt->errMax = 8;
1768 ctxt->errNr = 0;
1769 ctxt->errTab =
1770 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1771 sizeof
1772 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001773 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001774 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001775 return (0);
1776 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001777 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001778 }
1779 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001780 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001781 ctxt->errTab =
1782 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001783 ctxt->errMax *
1784 sizeof
1785 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001786 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001787 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001788 return (0);
1789 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001790 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001791 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001792 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001793 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1794 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001795 cur = &ctxt->errTab[ctxt->errNr];
1796 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001797 if (dup) {
1798 cur->arg1 = xmlStrdup(arg1);
1799 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001800 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001801 } else {
1802 cur->arg1 = arg1;
1803 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001804 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001805 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001806 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001807 cur->node = ctxt->state->node;
1808 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001809 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001810 cur->node = NULL;
1811 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001812 }
1813 ctxt->err = cur;
1814 return (ctxt->errNr++);
1815}
1816
1817/**
1818 * xmlRelaxNGValidErrorPop:
1819 * @ctxt: the validation context
1820 *
1821 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001822 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001823static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001824xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1825{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001826 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001827
Daniel Veillard580ced82003-03-21 21:22:48 +00001828 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001829 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001830 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001831 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001832 ctxt->errNr--;
1833 if (ctxt->errNr > 0)
1834 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1835 else
1836 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001837 cur = &ctxt->errTab[ctxt->errNr];
1838 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001839 if (cur->arg1 != NULL)
1840 xmlFree((xmlChar *) cur->arg1);
1841 cur->arg1 = NULL;
1842 if (cur->arg2 != NULL)
1843 xmlFree((xmlChar *) cur->arg2);
1844 cur->arg2 = NULL;
1845 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001846 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001847}
1848
Daniel Veillard42f12e92003-03-07 18:32:59 +00001849/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001850 * xmlRelaxNGDocumentPush:
1851 * @ctxt: the parser context
1852 * @value: the element doc
1853 *
1854 * Pushes a new doc on top of the doc stack
1855 *
1856 * Returns 0 in case of error, the index in the stack otherwise
1857 */
1858static int
1859xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001860 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001861{
1862 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001863 ctxt->docMax = 4;
1864 ctxt->docNr = 0;
1865 ctxt->docTab =
1866 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1867 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001868 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001869 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001870 return (0);
1871 }
1872 }
1873 if (ctxt->docNr >= ctxt->docMax) {
1874 ctxt->docMax *= 2;
1875 ctxt->docTab =
1876 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001877 ctxt->docMax *
1878 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001879 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001880 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001881 return (0);
1882 }
1883 }
1884 ctxt->docTab[ctxt->docNr] = value;
1885 ctxt->doc = value;
1886 return (ctxt->docNr++);
1887}
1888
1889/**
1890 * xmlRelaxNGDocumentPop:
1891 * @ctxt: the parser context
1892 *
1893 * Pops the top doc from the doc stack
1894 *
1895 * Returns the doc just removed
1896 */
1897static xmlRelaxNGDocumentPtr
1898xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1899{
1900 xmlRelaxNGDocumentPtr ret;
1901
1902 if (ctxt->docNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +00001903 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001904 ctxt->docNr--;
1905 if (ctxt->docNr > 0)
1906 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1907 else
1908 ctxt->doc = NULL;
1909 ret = ctxt->docTab[ctxt->docNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001910 ctxt->docTab[ctxt->docNr] = NULL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001911 return (ret);
1912}
1913
1914/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001915 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001916 * @ctxt: the parser context
1917 * @URL: the normalized URL
1918 * @ns: the inherited ns if any
1919 *
1920 * First lookup if the document is already loaded into the parser context,
1921 * check against recursion. If not found the resource is loaded and
1922 * the content is preprocessed before being returned back to the caller.
1923 *
1924 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1925 */
1926static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001927xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1928 const xmlChar * URL, const xmlChar * ns)
1929{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001930 xmlRelaxNGDocumentPtr ret = NULL;
1931 xmlDocPtr doc;
1932 xmlNodePtr root;
1933 int i;
1934
1935 /*
1936 * check against recursion in the stack
1937 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001938 for (i = 0; i < ctxt->docNr; i++) {
1939 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1940 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1941 "Detected an externalRef recursion for %s\n", URL,
1942 NULL);
1943 return (NULL);
1944 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001945 }
1946
1947 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001948 * load the document
1949 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001950 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001951 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001952 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1953 "xmlRelaxNG: could not load %s\n", URL, NULL);
1954 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001955 }
1956
1957 /*
1958 * Allocate the document structures and register it first.
1959 */
1960 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1961 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001962 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1963 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1964 xmlFreeDoc(doc);
1965 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001966 }
1967 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1968 ret->doc = doc;
1969 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001970 ret->next = ctxt->documents;
1971 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001972
1973 /*
1974 * transmit the ns if needed
1975 */
1976 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001977 root = xmlDocGetRootElement(doc);
1978 if (root != NULL) {
1979 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1980 xmlSetProp(root, BAD_CAST "ns", ns);
1981 }
1982 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001983 }
1984
1985 /*
1986 * push it on the stack and register it in the hash table
1987 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001988 xmlRelaxNGDocumentPush(ctxt, ret);
1989
1990 /*
1991 * Some preprocessing of the document content
1992 */
1993 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1994 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001995 ctxt->doc = NULL;
1996 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001997 }
1998
1999 xmlRelaxNGDocumentPop(ctxt);
2000
Daniel Veillard4c004142003-10-07 11:33:24 +00002001 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002002}
2003
2004/************************************************************************
2005 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002006 * Error functions *
2007 * *
2008 ************************************************************************/
2009
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002010#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2011#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2012#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2013#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2014#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002015
Daniel Veillard231d7912003-02-09 14:22:17 +00002016static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00002017xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2018{
Daniel Veillard231d7912003-02-09 14:22:17 +00002019 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002020 return ("none");
2021 switch (def->type) {
2022 case XML_RELAXNG_EMPTY:
2023 return ("empty");
2024 case XML_RELAXNG_NOT_ALLOWED:
2025 return ("notAllowed");
2026 case XML_RELAXNG_EXCEPT:
2027 return ("except");
2028 case XML_RELAXNG_TEXT:
2029 return ("text");
2030 case XML_RELAXNG_ELEMENT:
2031 return ("element");
2032 case XML_RELAXNG_DATATYPE:
2033 return ("datatype");
2034 case XML_RELAXNG_VALUE:
2035 return ("value");
2036 case XML_RELAXNG_LIST:
2037 return ("list");
2038 case XML_RELAXNG_ATTRIBUTE:
2039 return ("attribute");
2040 case XML_RELAXNG_DEF:
2041 return ("def");
2042 case XML_RELAXNG_REF:
2043 return ("ref");
2044 case XML_RELAXNG_EXTERNALREF:
2045 return ("externalRef");
2046 case XML_RELAXNG_PARENTREF:
2047 return ("parentRef");
2048 case XML_RELAXNG_OPTIONAL:
2049 return ("optional");
2050 case XML_RELAXNG_ZEROORMORE:
2051 return ("zeroOrMore");
2052 case XML_RELAXNG_ONEORMORE:
2053 return ("oneOrMore");
2054 case XML_RELAXNG_CHOICE:
2055 return ("choice");
2056 case XML_RELAXNG_GROUP:
2057 return ("group");
2058 case XML_RELAXNG_INTERLEAVE:
2059 return ("interleave");
2060 case XML_RELAXNG_START:
2061 return ("start");
2062 case XML_RELAXNG_NOOP:
2063 return ("noop");
2064 case XML_RELAXNG_PARAM:
2065 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002066 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002067 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002068}
Daniel Veillardd2298792003-02-14 16:54:11 +00002069
Daniel Veillard6eadf632003-01-23 18:29:16 +00002070/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002071 * xmlRelaxNGGetErrorString:
2072 * @err: the error code
2073 * @arg1: the first string argument
2074 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002075 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002076 * computes a formatted error string for the given error code and args
2077 *
2078 * Returns the error string, it must be deallocated by the caller
2079 */
2080static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002081xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2082 const xmlChar * arg2)
2083{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002084 char msg[1000];
2085
2086 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002087 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002088 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002089 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002090
2091 msg[0] = 0;
2092 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002093 case XML_RELAXNG_OK:
2094 return (NULL);
2095 case XML_RELAXNG_ERR_MEMORY:
2096 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002097 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002098 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2099 break;
2100 case XML_RELAXNG_ERR_TYPEVAL:
2101 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2102 arg2);
2103 break;
2104 case XML_RELAXNG_ERR_DUPID:
2105 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2106 break;
2107 case XML_RELAXNG_ERR_TYPECMP:
2108 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2109 break;
2110 case XML_RELAXNG_ERR_NOSTATE:
2111 return (xmlCharStrdup("Internal error: no state\n"));
2112 case XML_RELAXNG_ERR_NODEFINE:
2113 return (xmlCharStrdup("Internal error: no define\n"));
2114 case XML_RELAXNG_ERR_INTERNAL:
2115 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2116 break;
2117 case XML_RELAXNG_ERR_LISTEXTRA:
2118 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2119 break;
2120 case XML_RELAXNG_ERR_INTERNODATA:
2121 return (xmlCharStrdup
2122 ("Internal: interleave block has no data\n"));
2123 case XML_RELAXNG_ERR_INTERSEQ:
2124 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2125 case XML_RELAXNG_ERR_INTEREXTRA:
2126 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2127 break;
2128 case XML_RELAXNG_ERR_ELEMNAME:
2129 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2130 arg2);
2131 break;
2132 case XML_RELAXNG_ERR_ELEMNONS:
2133 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2134 arg1);
2135 break;
2136 case XML_RELAXNG_ERR_ELEMWRONGNS:
2137 snprintf(msg, 1000,
2138 "Element %s has wrong namespace: expecting %s\n", arg1,
2139 arg2);
2140 break;
2141 case XML_RELAXNG_ERR_ELEMWRONG:
2142 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2143 break;
2144 case XML_RELAXNG_ERR_TEXTWRONG:
2145 snprintf(msg, 1000,
2146 "Did not expect text in element %s content\n", arg1);
2147 break;
2148 case XML_RELAXNG_ERR_ELEMEXTRANS:
2149 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2150 arg1);
2151 break;
2152 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2153 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2154 break;
2155 case XML_RELAXNG_ERR_NOELEM:
2156 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2157 arg1);
2158 break;
2159 case XML_RELAXNG_ERR_NOTELEM:
2160 return (xmlCharStrdup("Expecting an element got text\n"));
2161 case XML_RELAXNG_ERR_ATTRVALID:
2162 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2163 arg1);
2164 break;
2165 case XML_RELAXNG_ERR_CONTENTVALID:
2166 snprintf(msg, 1000, "Element %s failed to validate content\n",
2167 arg1);
2168 break;
2169 case XML_RELAXNG_ERR_EXTRACONTENT:
2170 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2171 arg1, arg2);
2172 break;
2173 case XML_RELAXNG_ERR_INVALIDATTR:
2174 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2175 arg1, arg2);
2176 break;
2177 case XML_RELAXNG_ERR_LACKDATA:
2178 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2179 arg1);
2180 break;
2181 case XML_RELAXNG_ERR_DATAELEM:
2182 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2183 arg1);
2184 break;
2185 case XML_RELAXNG_ERR_VALELEM:
2186 snprintf(msg, 1000, "Value element %s has child elements\n",
2187 arg1);
2188 break;
2189 case XML_RELAXNG_ERR_LISTELEM:
2190 snprintf(msg, 1000, "List element %s has child elements\n",
2191 arg1);
2192 break;
2193 case XML_RELAXNG_ERR_DATATYPE:
2194 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2195 break;
2196 case XML_RELAXNG_ERR_VALUE:
2197 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2198 break;
2199 case XML_RELAXNG_ERR_LIST:
2200 return (xmlCharStrdup("Error validating list\n"));
2201 case XML_RELAXNG_ERR_NOGRAMMAR:
2202 return (xmlCharStrdup("No top grammar defined\n"));
2203 case XML_RELAXNG_ERR_EXTRADATA:
2204 return (xmlCharStrdup("Extra data in the document\n"));
2205 default:
2206 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002207 }
2208 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002209 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002210 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002211 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002212 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002213}
2214
2215/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002216 * xmlRelaxNGShowValidError:
2217 * @ctxt: the validation context
2218 * @err: the error number
2219 * @node: the node
2220 * @child: the node child generating the problem.
2221 * @arg1: the first argument
2222 * @arg2: the second argument
2223 *
2224 * Show a validation error.
2225 */
2226static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002227xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2228 xmlRelaxNGValidErr err, xmlNodePtr node,
2229 xmlNodePtr child, const xmlChar * arg1,
2230 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002231{
2232 xmlChar *msg;
2233
Daniel Veillardb30ca312005-09-04 13:50:03 +00002234 if (ctxt->flags & FLAGS_NOERROR)
Daniel Veillardf03a8cd2005-09-04 12:01:57 +00002235 return;
2236
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002237#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002238 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002239#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002240 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2241 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002242 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002243
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002244 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002245 ctxt->errNo = err;
2246 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2247 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002248 xmlFree(msg);
2249}
2250
2251/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002252 * xmlRelaxNGPopErrors:
2253 * @ctxt: the validation context
2254 * @level: the error level in the stack
2255 *
2256 * pop and discard all errors until the given level is reached
2257 */
2258static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002259xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2260{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002261 int i;
2262 xmlRelaxNGValidErrorPtr err;
2263
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002264#ifdef DEBUG_ERROR
2265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002266 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002267#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002268 for (i = level; i < ctxt->errNr; i++) {
2269 err = &ctxt->errTab[i];
2270 if (err->flags & ERROR_IS_DUP) {
2271 if (err->arg1 != NULL)
2272 xmlFree((xmlChar *) err->arg1);
2273 err->arg1 = NULL;
2274 if (err->arg2 != NULL)
2275 xmlFree((xmlChar *) err->arg2);
2276 err->arg2 = NULL;
2277 err->flags = 0;
2278 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002279 }
2280 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002281 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002282 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002283}
Daniel Veillard4c004142003-10-07 11:33:24 +00002284
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002285/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002286 * xmlRelaxNGDumpValidError:
2287 * @ctxt: the validation context
2288 *
2289 * Show all validation error over a given index.
2290 */
2291static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002292xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2293{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002294 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002295 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002296
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002297#ifdef DEBUG_ERROR
2298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002299 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002300#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002301 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2302 err = &ctxt->errTab[i];
2303 if (k < MAX_ERROR) {
2304 for (j = 0; j < i; j++) {
2305 dup = &ctxt->errTab[j];
2306 if ((err->err == dup->err) && (err->node == dup->node) &&
2307 (xmlStrEqual(err->arg1, dup->arg1)) &&
2308 (xmlStrEqual(err->arg2, dup->arg2))) {
2309 goto skip;
2310 }
2311 }
2312 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2313 err->arg1, err->arg2);
2314 k++;
2315 }
2316 skip:
2317 if (err->flags & ERROR_IS_DUP) {
2318 if (err->arg1 != NULL)
2319 xmlFree((xmlChar *) err->arg1);
2320 err->arg1 = NULL;
2321 if (err->arg2 != NULL)
2322 xmlFree((xmlChar *) err->arg2);
2323 err->arg2 = NULL;
2324 err->flags = 0;
2325 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002326 }
2327 ctxt->errNr = 0;
2328}
Daniel Veillard4c004142003-10-07 11:33:24 +00002329
Daniel Veillard42f12e92003-03-07 18:32:59 +00002330/**
2331 * xmlRelaxNGAddValidError:
2332 * @ctxt: the validation context
2333 * @err: the error number
2334 * @arg1: the first argument
2335 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002336 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002337 *
2338 * Register a validation error, either generating it if it's sure
2339 * or stacking it for later handling if unsure.
2340 */
2341static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002342xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2343 xmlRelaxNGValidErr err, const xmlChar * arg1,
2344 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002345{
Daniel Veillardb30ca312005-09-04 13:50:03 +00002346 if (ctxt == NULL)
2347 return;
2348 if (ctxt->flags & FLAGS_NOERROR)
Daniel Veillard4c004142003-10-07 11:33:24 +00002349 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002350
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002351#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002352 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002353#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002354 /*
2355 * generate the error directly
2356 */
William M. Brack60929622004-03-27 17:54:18 +00002357 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2358 (ctxt->flags & FLAGS_NEGATIVE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002359 xmlNodePtr node, seq;
2360
2361 /*
2362 * Flush first any stacked error which might be the
2363 * real cause of the problem.
2364 */
2365 if (ctxt->errNr != 0)
2366 xmlRelaxNGDumpValidError(ctxt);
2367 if (ctxt->state != NULL) {
2368 node = ctxt->state->node;
2369 seq = ctxt->state->seq;
2370 } else {
2371 node = seq = NULL;
2372 }
2373 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002374 }
2375 /*
2376 * Stack the error for later processing if needed
2377 */
2378 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002379 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002380 }
2381}
2382
Daniel Veillard6eadf632003-01-23 18:29:16 +00002383
2384/************************************************************************
2385 * *
2386 * Type library hooks *
2387 * *
2388 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002389static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002390 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002391
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002392/**
2393 * xmlRelaxNGSchemaTypeHave:
2394 * @data: data needed for the library
2395 * @type: the type name
2396 *
2397 * Check if the given type is provided by
2398 * the W3C XMLSchema Datatype library.
2399 *
2400 * Returns 1 if yes, 0 if no and -1 in case of error.
2401 */
2402static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002403xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2404{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002405 xmlSchemaTypePtr typ;
2406
2407 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002408 return (-1);
2409 typ = xmlSchemaGetPredefinedType(type,
2410 BAD_CAST
2411 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002412 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002413 return (0);
2414 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002415}
2416
2417/**
2418 * xmlRelaxNGSchemaTypeCheck:
2419 * @data: data needed for the library
2420 * @type: the type name
2421 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002422 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002423 *
2424 * Check if the given type and value are validated by
2425 * the W3C XMLSchema Datatype library.
2426 *
2427 * Returns 1 if yes, 0 if no and -1 in case of error.
2428 */
2429static int
2430xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002431 const xmlChar * type,
2432 const xmlChar * value,
2433 void **result, xmlNodePtr node)
2434{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002435 xmlSchemaTypePtr typ;
2436 int ret;
2437
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002438 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002439 return (-1);
2440 typ = xmlSchemaGetPredefinedType(type,
2441 BAD_CAST
2442 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002443 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002444 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002445 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002446 (xmlSchemaValPtr *) result, node);
2447 if (ret == 2) /* special ID error code */
2448 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002449 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002450 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002451 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002452 return (0);
2453 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002454}
2455
2456/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002457 * xmlRelaxNGSchemaFacetCheck:
2458 * @data: data needed for the library
2459 * @type: the type name
2460 * @facet: the facet name
2461 * @val: the facet value
2462 * @strval: the string value
2463 * @value: the value to check
2464 *
2465 * Function provided by a type library to check a value facet
2466 *
2467 * Returns 1 if yes, 0 if no and -1 in case of error.
2468 */
2469static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002470xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2471 const xmlChar * type, const xmlChar * facetname,
2472 const xmlChar * val, const xmlChar * strval,
2473 void *value)
2474{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002475 xmlSchemaFacetPtr facet;
2476 xmlSchemaTypePtr typ;
2477 int ret;
2478
2479 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002480 return (-1);
2481 typ = xmlSchemaGetPredefinedType(type,
2482 BAD_CAST
2483 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002484 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002485 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002486
2487 facet = xmlSchemaNewFacet();
2488 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002489 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002490
Daniel Veillard4c004142003-10-07 11:33:24 +00002491 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002492 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002493 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002494 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002495 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002496 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002497 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002498 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002499 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002500 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002501 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002502 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002503 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002504 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002505 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002506 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002507 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002508 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002509 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002510 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002511 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002512 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2513 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2514 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2515 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002516 xmlSchemaFreeFacet(facet);
2517 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002518 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002519 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002520 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2521 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002522 xmlSchemaFreeFacet(facet);
2523 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002524 }
2525 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2526 xmlSchemaFreeFacet(facet);
2527 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002528 return (-1);
2529 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002530}
2531
2532/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002533 * xmlRelaxNGSchemaFreeValue:
2534 * @data: data needed for the library
2535 * @value: the value to free
2536 *
2537 * Function provided by a type library to free a Schemas value
2538 *
2539 * Returns 1 if yes, 0 if no and -1 in case of error.
2540 */
2541static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002542xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2543{
Daniel Veillard80b19092003-03-28 13:29:53 +00002544 xmlSchemaFreeValue(value);
2545}
2546
2547/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002548 * xmlRelaxNGSchemaTypeCompare:
2549 * @data: data needed for the library
2550 * @type: the type name
2551 * @value1: the first value
2552 * @value2: the second value
2553 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002554 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002555 * Datatype library.
2556 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002557 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002558 */
2559static int
2560xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002561 const xmlChar * type,
2562 const xmlChar * value1,
2563 xmlNodePtr ctxt1,
2564 void *comp1,
2565 const xmlChar * value2, xmlNodePtr ctxt2)
2566{
Daniel Veillard80b19092003-03-28 13:29:53 +00002567 int ret;
2568 xmlSchemaTypePtr typ;
2569 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2570
2571 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002572 return (-1);
2573 typ = xmlSchemaGetPredefinedType(type,
2574 BAD_CAST
2575 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002576 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002577 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002578 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002579 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2580 if (ret != 0)
2581 return (-1);
2582 if (res1 == NULL)
2583 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002584 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002585 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002586 }
2587 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002588 if (ret != 0) {
Daniel Veillardf4644032005-06-13 11:41:31 +00002589 if ((comp1 == NULL) && (res1 != NULL))
2590 xmlSchemaFreeValue(res1);
Daniel Veillard4c004142003-10-07 11:33:24 +00002591 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002592 }
2593 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002594 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002595 }
2596 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002597 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002598 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002599 xmlSchemaFreeValue(res2);
2600 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002601 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002602 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002603 return (1);
2604 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002605}
Daniel Veillard4c004142003-10-07 11:33:24 +00002606
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002607/**
2608 * xmlRelaxNGDefaultTypeHave:
2609 * @data: data needed for the library
2610 * @type: the type name
2611 *
2612 * Check if the given type is provided by
2613 * the default datatype library.
2614 *
2615 * Returns 1 if yes, 0 if no and -1 in case of error.
2616 */
2617static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002618xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2619 const xmlChar * type)
2620{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002621 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002622 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002623 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002624 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002625 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002626 return (1);
2627 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002628}
2629
2630/**
2631 * xmlRelaxNGDefaultTypeCheck:
2632 * @data: data needed for the library
2633 * @type: the type name
2634 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002635 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002636 *
2637 * Check if the given type and value are validated by
2638 * the default datatype library.
2639 *
2640 * Returns 1 if yes, 0 if no and -1 in case of error.
2641 */
2642static int
2643xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002644 const xmlChar * type ATTRIBUTE_UNUSED,
2645 const xmlChar * value ATTRIBUTE_UNUSED,
2646 void **result ATTRIBUTE_UNUSED,
2647 xmlNodePtr node ATTRIBUTE_UNUSED)
2648{
Daniel Veillardd4310742003-02-18 21:12:46 +00002649 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002650 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002651 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002652 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002653 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002654 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002655 }
2656
Daniel Veillard4c004142003-10-07 11:33:24 +00002657 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002658}
2659
2660/**
2661 * xmlRelaxNGDefaultTypeCompare:
2662 * @data: data needed for the library
2663 * @type: the type name
2664 * @value1: the first value
2665 * @value2: the second value
2666 *
2667 * Compare two values accordingly a type from the default
2668 * datatype library.
2669 *
2670 * Returns 1 if yes, 0 if no and -1 in case of error.
2671 */
2672static int
2673xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002674 const xmlChar * type,
2675 const xmlChar * value1,
2676 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2677 void *comp1 ATTRIBUTE_UNUSED,
2678 const xmlChar * value2,
2679 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2680{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002681 int ret = -1;
2682
2683 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002684 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002685 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002686 if (!xmlStrEqual(value1, value2)) {
2687 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002688
Daniel Veillard4c004142003-10-07 11:33:24 +00002689 /*
2690 * TODO: trivial optimizations are possible by
2691 * computing at compile-time
2692 */
2693 nval = xmlRelaxNGNormalize(NULL, value1);
2694 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002695
Daniel Veillard4c004142003-10-07 11:33:24 +00002696 if ((nval == NULL) || (nvalue == NULL))
2697 ret = -1;
2698 else if (xmlStrEqual(nval, nvalue))
2699 ret = 1;
2700 else
2701 ret = 0;
2702 if (nval != NULL)
2703 xmlFree(nval);
2704 if (nvalue != NULL)
2705 xmlFree(nvalue);
2706 } else
2707 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002708 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002709 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002710}
Daniel Veillard4c004142003-10-07 11:33:24 +00002711
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002712static int xmlRelaxNGTypeInitialized = 0;
2713static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2714
2715/**
2716 * xmlRelaxNGFreeTypeLibrary:
2717 * @lib: the type library structure
2718 * @namespace: the URI bound to the library
2719 *
2720 * Free the structure associated to the type library
2721 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002722static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002723xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002724 const xmlChar * namespace ATTRIBUTE_UNUSED)
2725{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002726 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002727 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002728 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002729 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002730 xmlFree(lib);
2731}
2732
2733/**
2734 * xmlRelaxNGRegisterTypeLibrary:
2735 * @namespace: the URI bound to the library
2736 * @data: data associated to the library
2737 * @have: the provide function
2738 * @check: the checking function
2739 * @comp: the comparison function
2740 *
2741 * Register a new type library
2742 *
2743 * Returns 0 in case of success and -1 in case of error.
2744 */
2745static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002746xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2747 xmlRelaxNGTypeHave have,
2748 xmlRelaxNGTypeCheck check,
2749 xmlRelaxNGTypeCompare comp,
2750 xmlRelaxNGFacetCheck facet,
2751 xmlRelaxNGTypeFree freef)
2752{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002753 xmlRelaxNGTypeLibraryPtr lib;
2754 int ret;
2755
2756 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002757 (check == NULL) || (comp == NULL))
2758 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002759 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002760 xmlGenericError(xmlGenericErrorContext,
2761 "Relax-NG types library '%s' already registered\n",
2762 namespace);
2763 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002764 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002765 lib =
2766 (xmlRelaxNGTypeLibraryPtr)
2767 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002768 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002769 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002770 return (-1);
2771 }
2772 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2773 lib->namespace = xmlStrdup(namespace);
2774 lib->data = data;
2775 lib->have = have;
2776 lib->comp = comp;
2777 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002778 lib->facet = facet;
2779 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002780 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2781 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002782 xmlGenericError(xmlGenericErrorContext,
2783 "Relax-NG types library failed to register '%s'\n",
2784 namespace);
2785 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2786 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002787 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002788 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002789}
2790
2791/**
2792 * xmlRelaxNGInitTypes:
2793 *
2794 * Initilize the default type libraries.
2795 *
2796 * Returns 0 in case of success and -1 in case of error.
2797 */
Daniel Veillarddd6d3002004-11-03 14:20:29 +00002798int
Daniel Veillard4c004142003-10-07 11:33:24 +00002799xmlRelaxNGInitTypes(void)
2800{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002801 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002802 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002803 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2804 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002805 xmlGenericError(xmlGenericErrorContext,
2806 "Failed to allocate sh table for Relax-NG types\n");
2807 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002808 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002809 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2810 "http://www.w3.org/2001/XMLSchema-datatypes",
2811 NULL, xmlRelaxNGSchemaTypeHave,
2812 xmlRelaxNGSchemaTypeCheck,
2813 xmlRelaxNGSchemaTypeCompare,
2814 xmlRelaxNGSchemaFacetCheck,
2815 xmlRelaxNGSchemaFreeValue);
2816 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2817 xmlRelaxNGDefaultTypeHave,
2818 xmlRelaxNGDefaultTypeCheck,
2819 xmlRelaxNGDefaultTypeCompare, NULL,
2820 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002821 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002822 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002823}
2824
2825/**
2826 * xmlRelaxNGCleanupTypes:
2827 *
2828 * Cleanup the default Schemas type library associated to RelaxNG
2829 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002830void
2831xmlRelaxNGCleanupTypes(void)
2832{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002833 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002834 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002835 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002836 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002837 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002838 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002839}
2840
2841/************************************************************************
2842 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002843 * Compiling element content into regexp *
2844 * *
2845 * Sometime the element content can be compiled into a pure regexp, *
2846 * This allows a faster execution and streamability at that level *
2847 * *
2848 ************************************************************************/
2849
Daniel Veillard52b48c72003-04-13 19:53:42 +00002850static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2851 xmlRelaxNGDefinePtr def);
2852
Daniel Veillard952379b2003-03-17 15:37:12 +00002853/**
2854 * xmlRelaxNGIsCompileable:
2855 * @define: the definition to check
2856 *
2857 * Check if a definition is nullable.
2858 *
2859 * Returns 1 if yes, 0 if no and -1 in case of error
2860 */
2861static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002862xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2863{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002864 int ret = -1;
2865
Daniel Veillard952379b2003-03-17 15:37:12 +00002866 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002867 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002868 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002869 if ((def->type != XML_RELAXNG_ELEMENT) &&
2870 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002871 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002872 if ((def->type != XML_RELAXNG_ELEMENT) &&
2873 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002874 return (0);
2875 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002876 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002877 ret = xmlRelaxNGIsCompileable(def->content);
2878 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002879 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002880 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002881 ret = 1;
2882 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002883 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002884 /*
2885 * Check if the element content is compileable
2886 */
2887 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2888 ((def->dflags & IS_COMPILABLE) == 0)) {
2889 xmlRelaxNGDefinePtr list;
2890
2891 list = def->content;
2892 while (list != NULL) {
2893 ret = xmlRelaxNGIsCompileable(list);
2894 if (ret != 1)
2895 break;
2896 list = list->next;
2897 }
William M. Brack60929622004-03-27 17:54:18 +00002898 /*
2899 * Because the routine is recursive, we must guard against
2900 * discovering both COMPILABLE and NOT_COMPILABLE
2901 */
2902 if (ret == 0) {
2903 def->dflags &= ~IS_COMPILABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002904 def->dflags |= IS_NOT_COMPILABLE;
William M. Brack60929622004-03-27 17:54:18 +00002905 }
2906 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002907 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002908#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002909 if (ret == 1) {
2910 xmlGenericError(xmlGenericErrorContext,
2911 "element content for %s is compilable\n",
2912 def->name);
2913 } else if (ret == 0) {
2914 xmlGenericError(xmlGenericErrorContext,
2915 "element content for %s is not compilable\n",
2916 def->name);
2917 } else {
2918 xmlGenericError(xmlGenericErrorContext,
2919 "Problem in RelaxNGIsCompileable for element %s\n",
2920 def->name);
2921 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002922#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002923 }
2924 /*
2925 * All elements return a compileable status unless they
2926 * are generic like anyName
2927 */
2928 if ((def->nameClass != NULL) || (def->name == NULL))
2929 ret = 0;
2930 else
2931 ret = 1;
2932 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002933 case XML_RELAXNG_REF:
2934 case XML_RELAXNG_EXTERNALREF:
2935 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002936 if (def->depth == -20) {
2937 return (1);
2938 } else {
2939 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002940
Daniel Veillard4c004142003-10-07 11:33:24 +00002941 def->depth = -20;
2942 list = def->content;
2943 while (list != NULL) {
2944 ret = xmlRelaxNGIsCompileable(list);
2945 if (ret != 1)
2946 break;
2947 list = list->next;
2948 }
2949 }
2950 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002951 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002952 case XML_RELAXNG_OPTIONAL:
2953 case XML_RELAXNG_ZEROORMORE:
2954 case XML_RELAXNG_ONEORMORE:
2955 case XML_RELAXNG_CHOICE:
2956 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002957 case XML_RELAXNG_DEF:{
2958 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002959
Daniel Veillard4c004142003-10-07 11:33:24 +00002960 list = def->content;
2961 while (list != NULL) {
2962 ret = xmlRelaxNGIsCompileable(list);
2963 if (ret != 1)
2964 break;
2965 list = list->next;
2966 }
2967 break;
2968 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002969 case XML_RELAXNG_EXCEPT:
2970 case XML_RELAXNG_ATTRIBUTE:
2971 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002972 case XML_RELAXNG_DATATYPE:
2973 case XML_RELAXNG_LIST:
2974 case XML_RELAXNG_PARAM:
2975 case XML_RELAXNG_VALUE:
Daniel Veillard952379b2003-03-17 15:37:12 +00002976 case XML_RELAXNG_NOT_ALLOWED:
William M. Brack7e29c0a2004-04-02 09:07:22 +00002977 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002978 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002979 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002980 if (ret == 0)
2981 def->dflags |= IS_NOT_COMPILABLE;
2982 if (ret == 1)
2983 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002984#ifdef DEBUG_COMPILE
2985 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002986 xmlGenericError(xmlGenericErrorContext,
2987 "RelaxNGIsCompileable %s : true\n",
2988 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002989 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002990 xmlGenericError(xmlGenericErrorContext,
2991 "RelaxNGIsCompileable %s : false\n",
2992 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002993 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002994 xmlGenericError(xmlGenericErrorContext,
2995 "Problem in RelaxNGIsCompileable %s\n",
2996 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002997 }
2998#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002999 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003000}
3001
3002/**
3003 * xmlRelaxNGCompile:
3004 * ctxt: the RelaxNG parser context
3005 * @define: the definition tree to compile
3006 *
3007 * Compile the set of definitions, it works recursively, till the
3008 * element boundaries, where it tries to compile the content if possible
3009 *
3010 * Returns 0 if success and -1 in case of error
3011 */
3012static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003013xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3014{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003015 int ret = 0;
3016 xmlRelaxNGDefinePtr list;
3017
Daniel Veillard4c004142003-10-07 11:33:24 +00003018 if ((ctxt == NULL) || (def == NULL))
3019 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003020
Daniel Veillard4c004142003-10-07 11:33:24 +00003021 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003022 case XML_RELAXNG_START:
3023 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003024 xmlAutomataPtr oldam = ctxt->am;
3025 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003026
3027 def->depth = -25;
3028
Daniel Veillard4c004142003-10-07 11:33:24 +00003029 list = def->content;
3030 ctxt->am = xmlNewAutomata();
3031 if (ctxt->am == NULL)
3032 return (-1);
3033 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3034 while (list != NULL) {
3035 xmlRelaxNGCompile(ctxt, list);
3036 list = list->next;
3037 }
3038 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3039 def->contModel = xmlAutomataCompile(ctxt->am);
3040 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003041
Daniel Veillard4c004142003-10-07 11:33:24 +00003042 xmlFreeAutomata(ctxt->am);
3043 ctxt->state = oldstate;
3044 ctxt->am = oldam;
3045 }
3046 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003047 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003048 if ((ctxt->am != NULL) && (def->name != NULL)) {
3049 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3050 ctxt->state, NULL,
3051 def->name, def->ns,
3052 def);
3053 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003054 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003055 xmlAutomataPtr oldam = ctxt->am;
3056 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003057
3058 def->depth = -25;
3059
Daniel Veillard4c004142003-10-07 11:33:24 +00003060 list = def->content;
3061 ctxt->am = xmlNewAutomata();
3062 if (ctxt->am == NULL)
3063 return (-1);
3064 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3065 while (list != NULL) {
3066 xmlRelaxNGCompile(ctxt, list);
3067 list = list->next;
3068 }
3069 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3070 def->contModel = xmlAutomataCompile(ctxt->am);
3071 if (!xmlRegexpIsDeterminist(def->contModel)) {
3072 /*
3073 * we can only use the automata if it is determinist
3074 */
3075 xmlRegFreeRegexp(def->contModel);
3076 def->contModel = NULL;
3077 }
3078 xmlFreeAutomata(ctxt->am);
3079 ctxt->state = oldstate;
3080 ctxt->am = oldam;
3081 } else {
3082 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003083
Daniel Veillard4c004142003-10-07 11:33:24 +00003084 /*
3085 * we can't build the content model for this element content
3086 * but it still might be possible to build it for some of its
3087 * children, recurse.
3088 */
3089 ret = xmlRelaxNGTryCompile(ctxt, def);
3090 ctxt->am = oldam;
3091 }
3092 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003093 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003094 ret = xmlRelaxNGCompile(ctxt, def->content);
3095 break;
3096 case XML_RELAXNG_OPTIONAL:{
3097 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003098
Daniel Veillard4c004142003-10-07 11:33:24 +00003099 xmlRelaxNGCompile(ctxt, def->content);
3100 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3101 break;
3102 }
3103 case XML_RELAXNG_ZEROORMORE:{
3104 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003105
Daniel Veillard4c004142003-10-07 11:33:24 +00003106 ctxt->state =
3107 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3108 oldstate = ctxt->state;
3109 list = def->content;
3110 while (list != NULL) {
3111 xmlRelaxNGCompile(ctxt, list);
3112 list = list->next;
3113 }
3114 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3115 ctxt->state =
3116 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3117 break;
3118 }
3119 case XML_RELAXNG_ONEORMORE:{
3120 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003121
Daniel Veillard4c004142003-10-07 11:33:24 +00003122 list = def->content;
3123 while (list != NULL) {
3124 xmlRelaxNGCompile(ctxt, list);
3125 list = list->next;
3126 }
3127 oldstate = ctxt->state;
3128 list = def->content;
3129 while (list != NULL) {
3130 xmlRelaxNGCompile(ctxt, list);
3131 list = list->next;
3132 }
3133 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3134 ctxt->state =
3135 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3136 break;
3137 }
3138 case XML_RELAXNG_CHOICE:{
3139 xmlAutomataStatePtr target = NULL;
3140 xmlAutomataStatePtr oldstate = ctxt->state;
3141
3142 list = def->content;
3143 while (list != NULL) {
3144 ctxt->state = oldstate;
3145 ret = xmlRelaxNGCompile(ctxt, list);
3146 if (ret != 0)
3147 break;
3148 if (target == NULL)
3149 target = ctxt->state;
3150 else {
3151 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3152 target);
3153 }
3154 list = list->next;
3155 }
3156 ctxt->state = target;
3157
3158 break;
3159 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003160 case XML_RELAXNG_REF:
3161 case XML_RELAXNG_EXTERNALREF:
3162 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003163 case XML_RELAXNG_GROUP:
3164 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003165 list = def->content;
3166 while (list != NULL) {
3167 ret = xmlRelaxNGCompile(ctxt, list);
3168 if (ret != 0)
3169 break;
3170 list = list->next;
3171 }
3172 break;
3173 case XML_RELAXNG_TEXT:{
3174 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003175
Daniel Veillard4c004142003-10-07 11:33:24 +00003176 ctxt->state =
3177 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3178 oldstate = ctxt->state;
3179 xmlRelaxNGCompile(ctxt, def->content);
3180 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3181 ctxt->state, BAD_CAST "#text",
3182 NULL);
3183 ctxt->state =
3184 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3185 break;
3186 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003187 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003188 ctxt->state =
3189 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3190 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003191 case XML_RELAXNG_EXCEPT:
3192 case XML_RELAXNG_ATTRIBUTE:
3193 case XML_RELAXNG_INTERLEAVE:
3194 case XML_RELAXNG_NOT_ALLOWED:
3195 case XML_RELAXNG_DATATYPE:
3196 case XML_RELAXNG_LIST:
3197 case XML_RELAXNG_PARAM:
3198 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003199 /* This should not happen and generate an internal error */
3200 fprintf(stderr, "RNG internal error trying to compile %s\n",
3201 xmlRelaxNGDefName(def));
3202 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003203 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003204 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003205}
3206
3207/**
3208 * xmlRelaxNGTryCompile:
3209 * ctxt: the RelaxNG parser context
3210 * @define: the definition tree to compile
3211 *
3212 * Try to compile the set of definitions, it works recursively,
3213 * possibly ignoring parts which cannot be compiled.
3214 *
3215 * Returns 0 if success and -1 in case of error
3216 */
3217static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003218xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3219{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003220 int ret = 0;
3221 xmlRelaxNGDefinePtr list;
3222
Daniel Veillard4c004142003-10-07 11:33:24 +00003223 if ((ctxt == NULL) || (def == NULL))
3224 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003225
3226 if ((def->type == XML_RELAXNG_START) ||
3227 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003228 ret = xmlRelaxNGIsCompileable(def);
3229 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3230 ctxt->am = NULL;
3231 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003232#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003233 if (ret == 0) {
3234 if (def->type == XML_RELAXNG_START)
3235 xmlGenericError(xmlGenericErrorContext,
3236 "compiled the start\n");
3237 else
3238 xmlGenericError(xmlGenericErrorContext,
3239 "compiled element %s\n", def->name);
3240 } else {
3241 if (def->type == XML_RELAXNG_START)
3242 xmlGenericError(xmlGenericErrorContext,
3243 "failed to compile the start\n");
3244 else
3245 xmlGenericError(xmlGenericErrorContext,
3246 "failed to compile element %s\n",
3247 def->name);
3248 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003249#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003250 return (ret);
3251 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003252 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003253 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003254 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003255 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3256 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003257 case XML_RELAXNG_TEXT:
3258 case XML_RELAXNG_DATATYPE:
3259 case XML_RELAXNG_LIST:
3260 case XML_RELAXNG_PARAM:
3261 case XML_RELAXNG_VALUE:
3262 case XML_RELAXNG_EMPTY:
3263 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003264 ret = 0;
3265 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003266 case XML_RELAXNG_OPTIONAL:
3267 case XML_RELAXNG_ZEROORMORE:
3268 case XML_RELAXNG_ONEORMORE:
3269 case XML_RELAXNG_CHOICE:
3270 case XML_RELAXNG_GROUP:
3271 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003272 case XML_RELAXNG_START:
3273 case XML_RELAXNG_REF:
3274 case XML_RELAXNG_EXTERNALREF:
3275 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003276 list = def->content;
3277 while (list != NULL) {
3278 ret = xmlRelaxNGTryCompile(ctxt, list);
3279 if (ret != 0)
3280 break;
3281 list = list->next;
3282 }
3283 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003284 case XML_RELAXNG_EXCEPT:
3285 case XML_RELAXNG_ATTRIBUTE:
3286 case XML_RELAXNG_INTERLEAVE:
3287 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003288 ret = 0;
3289 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003290 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003291 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003292}
3293
3294/************************************************************************
3295 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003296 * Parsing functions *
3297 * *
3298 ************************************************************************/
3299
Daniel Veillard4c004142003-10-07 11:33:24 +00003300static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3301 ctxt, xmlNodePtr node);
3302static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3303 ctxt, xmlNodePtr node);
3304static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3305 ctxt, xmlNodePtr nodes,
3306 int group);
3307static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3308 ctxt, xmlNodePtr node);
3309static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3310 xmlNodePtr node);
3311static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3312 xmlNodePtr nodes);
3313static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3314 ctxt, xmlNodePtr node,
3315 xmlRelaxNGDefinePtr
3316 def);
3317static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3318 ctxt, xmlNodePtr nodes);
3319static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3320 xmlRelaxNGDefinePtr define,
3321 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003322
3323
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003324#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003325
3326/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003327 * xmlRelaxNGIsNullable:
3328 * @define: the definition to verify
3329 *
3330 * Check if a definition is nullable.
3331 *
3332 * Returns 1 if yes, 0 if no and -1 in case of error
3333 */
3334static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003335xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3336{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003337 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003338
Daniel Veillardfd573f12003-03-16 17:52:32 +00003339 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003340 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003341
Daniel Veillarde063f482003-03-21 16:53:17 +00003342 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003343 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003344 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003345 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003346 switch (define->type) {
3347 case XML_RELAXNG_EMPTY:
3348 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003349 ret = 1;
3350 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003351 case XML_RELAXNG_NOOP:
3352 case XML_RELAXNG_DEF:
3353 case XML_RELAXNG_REF:
3354 case XML_RELAXNG_EXTERNALREF:
3355 case XML_RELAXNG_PARENTREF:
3356 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003357 ret = xmlRelaxNGIsNullable(define->content);
3358 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003359 case XML_RELAXNG_EXCEPT:
3360 case XML_RELAXNG_NOT_ALLOWED:
3361 case XML_RELAXNG_ELEMENT:
3362 case XML_RELAXNG_DATATYPE:
3363 case XML_RELAXNG_PARAM:
3364 case XML_RELAXNG_VALUE:
3365 case XML_RELAXNG_LIST:
3366 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003367 ret = 0;
3368 break;
3369 case XML_RELAXNG_CHOICE:{
3370 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003371
Daniel Veillard4c004142003-10-07 11:33:24 +00003372 while (list != NULL) {
3373 ret = xmlRelaxNGIsNullable(list);
3374 if (ret != 0)
3375 goto done;
3376 list = list->next;
3377 }
3378 ret = 0;
3379 break;
3380 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003381 case XML_RELAXNG_START:
3382 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003383 case XML_RELAXNG_GROUP:{
3384 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003385
Daniel Veillard4c004142003-10-07 11:33:24 +00003386 while (list != NULL) {
3387 ret = xmlRelaxNGIsNullable(list);
3388 if (ret != 1)
3389 goto done;
3390 list = list->next;
3391 }
3392 return (1);
3393 }
3394 default:
3395 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003396 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003397 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003398 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003399 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003400 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003401 define->dflags |= IS_NULLABLE;
3402 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003403}
3404
3405/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003406 * xmlRelaxNGIsBlank:
3407 * @str: a string
3408 *
3409 * Check if a string is ignorable c.f. 4.2. Whitespace
3410 *
3411 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3412 */
3413static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003414xmlRelaxNGIsBlank(xmlChar * str)
3415{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003416 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003417 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003418 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003419 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003420 return (0);
3421 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003422 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003423 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003424}
3425
Daniel Veillard6eadf632003-01-23 18:29:16 +00003426/**
3427 * xmlRelaxNGGetDataTypeLibrary:
3428 * @ctxt: a Relax-NG parser context
3429 * @node: the current data or value element
3430 *
3431 * Applies algorithm from 4.3. datatypeLibrary attribute
3432 *
3433 * Returns the datatypeLibary value or NULL if not found
3434 */
3435static xmlChar *
3436xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003437 xmlNodePtr node)
3438{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003439 xmlChar *ret, *escape;
3440
Daniel Veillard6eadf632003-01-23 18:29:16 +00003441 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003442 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3443 if (ret != NULL) {
3444 if (ret[0] == 0) {
3445 xmlFree(ret);
3446 return (NULL);
3447 }
3448 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3449 if (escape == NULL) {
3450 return (ret);
3451 }
3452 xmlFree(ret);
3453 return (escape);
3454 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003455 }
3456 node = node->parent;
3457 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003458 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3459 if (ret != NULL) {
3460 if (ret[0] == 0) {
3461 xmlFree(ret);
3462 return (NULL);
3463 }
3464 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3465 if (escape == NULL) {
3466 return (ret);
3467 }
3468 xmlFree(ret);
3469 return (escape);
3470 }
3471 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003472 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003473 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003474}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003475
3476/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003477 * xmlRelaxNGParseValue:
3478 * @ctxt: a Relax-NG parser context
3479 * @node: the data node.
3480 *
3481 * parse the content of a RelaxNG value node.
3482 *
3483 * Returns the definition pointer or NULL in case of error
3484 */
3485static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003486xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3487{
Daniel Veillardedc91922003-01-26 00:52:04 +00003488 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003489 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003490 xmlChar *type;
3491 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003492 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003493
Daniel Veillardfd573f12003-03-16 17:52:32 +00003494 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003495 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003496 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003497 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003498
3499 type = xmlGetProp(node, BAD_CAST "type");
3500 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003501 xmlRelaxNGNormExtSpace(type);
3502 if (xmlValidateNCName(type, 0)) {
3503 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3504 "value type '%s' is not an NCName\n", type, NULL);
3505 }
3506 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3507 if (library == NULL)
3508 library =
3509 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003510
Daniel Veillard4c004142003-10-07 11:33:24 +00003511 def->name = type;
3512 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003513
Daniel Veillard4c004142003-10-07 11:33:24 +00003514 lib = (xmlRelaxNGTypeLibraryPtr)
3515 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3516 if (lib == NULL) {
3517 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3518 "Use of unregistered type library '%s'\n", library,
3519 NULL);
3520 def->data = NULL;
3521 } else {
3522 def->data = lib;
3523 if (lib->have == NULL) {
3524 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3525 "Internal error with type library '%s': no 'have'\n",
3526 library, NULL);
3527 } else {
3528 success = lib->have(lib->data, def->name);
3529 if (success != 1) {
3530 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3531 "Error type '%s' is not exported by type library '%s'\n",
3532 def->name, library);
3533 }
3534 }
3535 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003536 }
3537 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003538 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003539 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003540 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3541 (node->children->next != NULL)) {
3542 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3543 "Expecting a single text value for <value>content\n",
3544 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003545 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003546 def->value = xmlNodeGetContent(node);
3547 if (def->value == NULL) {
3548 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3549 "Element <value> has no content\n", NULL, NULL);
3550 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3551 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003552
Daniel Veillard4c004142003-10-07 11:33:24 +00003553 success =
3554 lib->check(lib->data, def->name, def->value, &val, node);
3555 if (success != 1) {
3556 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3557 "Value '%s' is not acceptable for type '%s'\n",
3558 def->value, def->name);
3559 } else {
3560 if (val != NULL)
3561 def->attrs = val;
3562 }
3563 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003564 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003565 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003566}
3567
3568/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003569 * xmlRelaxNGParseData:
3570 * @ctxt: a Relax-NG parser context
3571 * @node: the data node.
3572 *
3573 * parse the content of a RelaxNG data node.
3574 *
3575 * Returns the definition pointer or NULL in case of error
3576 */
3577static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003578xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3579{
Daniel Veillard416589a2003-02-17 17:25:42 +00003580 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003581 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003582 xmlRelaxNGTypeLibraryPtr lib;
3583 xmlChar *type;
3584 xmlChar *library;
3585 xmlNodePtr content;
3586 int tmp;
3587
3588 type = xmlGetProp(node, BAD_CAST "type");
3589 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003590 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3591 NULL);
3592 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003593 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003594 xmlRelaxNGNormExtSpace(type);
3595 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003596 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3597 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003598 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003599 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3600 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003601 library =
3602 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003603
Daniel Veillardfd573f12003-03-16 17:52:32 +00003604 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003605 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003606 xmlFree(type);
3607 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003608 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003609 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003610 def->name = type;
3611 def->ns = library;
3612
3613 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003614 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003615 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003616 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3617 "Use of unregistered type library '%s'\n", library,
3618 NULL);
3619 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003620 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003621 def->data = lib;
3622 if (lib->have == NULL) {
3623 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3624 "Internal error with type library '%s': no 'have'\n",
3625 library, NULL);
3626 } else {
3627 tmp = lib->have(lib->data, def->name);
3628 if (tmp != 1) {
3629 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3630 "Error type '%s' is not exported by type library '%s'\n",
3631 def->name, library);
3632 } else
3633 if ((xmlStrEqual
3634 (library,
3635 BAD_CAST
3636 "http://www.w3.org/2001/XMLSchema-datatypes"))
3637 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3638 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3639 ctxt->idref = 1;
3640 }
3641 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003642 }
3643 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003644
3645 /*
3646 * Handle optional params
3647 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003648 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003649 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3650 break;
3651 if (xmlStrEqual(library,
3652 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3653 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3654 "Type library '%s' does not allow type parameters\n",
3655 library, NULL);
3656 content = content->next;
3657 while ((content != NULL) &&
3658 (xmlStrEqual(content->name, BAD_CAST "param")))
3659 content = content->next;
3660 } else {
3661 param = xmlRelaxNGNewDefine(ctxt, node);
3662 if (param != NULL) {
3663 param->type = XML_RELAXNG_PARAM;
3664 param->name = xmlGetProp(content, BAD_CAST "name");
3665 if (param->name == NULL) {
3666 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3667 "param has no name\n", NULL, NULL);
3668 }
3669 param->value = xmlNodeGetContent(content);
3670 if (lastparam == NULL) {
3671 def->attrs = lastparam = param;
3672 } else {
3673 lastparam->next = param;
3674 lastparam = param;
3675 }
3676 if (lib != NULL) {
3677 }
3678 }
3679 content = content->next;
3680 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003681 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003682 /*
3683 * Handle optional except
3684 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003685 if ((content != NULL)
3686 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3687 xmlNodePtr child;
3688 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003689
Daniel Veillard4c004142003-10-07 11:33:24 +00003690 except = xmlRelaxNGNewDefine(ctxt, node);
3691 if (except == NULL) {
3692 return (def);
3693 }
3694 except->type = XML_RELAXNG_EXCEPT;
3695 child = content->children;
3696 if (last == NULL) {
3697 def->content = except;
3698 } else {
3699 last->next = except;
3700 }
3701 if (child == NULL) {
3702 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3703 "except has no content\n", NULL, NULL);
3704 }
3705 while (child != NULL) {
3706 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3707 if (tmp2 != NULL) {
3708 if (last2 == NULL) {
3709 except->content = last2 = tmp2;
3710 } else {
3711 last2->next = tmp2;
3712 last2 = tmp2;
3713 }
3714 }
3715 child = child->next;
3716 }
3717 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003718 }
3719 /*
3720 * Check there is no unhandled data
3721 */
3722 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003723 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3724 "Element data has unexpected content %s\n",
3725 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003726 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003727
Daniel Veillard4c004142003-10-07 11:33:24 +00003728 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003729}
3730
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003731static const xmlChar *invalidName = BAD_CAST "\1";
3732
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003733/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003734 * xmlRelaxNGCompareNameClasses:
3735 * @defs1: the first element/attribute defs
3736 * @defs2: the second element/attribute defs
3737 * @name: the restriction on the name
3738 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003739 *
3740 * Compare the 2 lists of element definitions. The comparison is
3741 * that if both lists do not accept the same QNames, it returns 1
3742 * If the 2 lists can accept the same QName the comparison returns 0
3743 *
3744 * Returns 1 disttinct, 0 if equal
3745 */
3746static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003747xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003748 xmlRelaxNGDefinePtr def2)
3749{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003750 int ret = 1;
3751 xmlNode node;
3752 xmlNs ns;
3753 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003754
Daniel Veillard42f12e92003-03-07 18:32:59 +00003755 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3756
Daniel Veillardb30ca312005-09-04 13:50:03 +00003757 ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3758
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003759 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003760 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3761 if (def2->type == XML_RELAXNG_TEXT)
3762 return (1);
3763 if (def1->name != NULL) {
3764 node.name = def1->name;
3765 } else {
3766 node.name = invalidName;
3767 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003768 if (def1->ns != NULL) {
3769 if (def1->ns[0] == 0) {
3770 node.ns = NULL;
3771 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003772 node.ns = &ns;
Daniel Veillard4c004142003-10-07 11:33:24 +00003773 ns.href = def1->ns;
3774 }
3775 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003776 node.ns = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00003777 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003778 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003779 if (def1->nameClass != NULL) {
3780 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3781 } else {
3782 ret = 0;
3783 }
3784 } else {
3785 ret = 1;
3786 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003787 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003788 if (def2->type == XML_RELAXNG_TEXT)
3789 return (0);
3790 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003791 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003792 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003793 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003794 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003795 }
3796 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003797 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003798 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003799 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3800 if (def2->name != NULL) {
3801 node.name = def2->name;
3802 } else {
3803 node.name = invalidName;
3804 }
3805 node.ns = &ns;
3806 if (def2->ns != NULL) {
3807 if (def2->ns[0] == 0) {
3808 node.ns = NULL;
3809 } else {
3810 ns.href = def2->ns;
3811 }
3812 } else {
3813 ns.href = invalidName;
3814 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003815 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003816 if (def2->nameClass != NULL) {
3817 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3818 } else {
3819 ret = 0;
3820 }
3821 } else {
3822 ret = 1;
3823 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003824 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003825 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003826 }
3827
Daniel Veillard4c004142003-10-07 11:33:24 +00003828 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003829}
3830
3831/**
3832 * xmlRelaxNGCompareElemDefLists:
3833 * @ctxt: a Relax-NG parser context
3834 * @defs1: the first list of element/attribute defs
3835 * @defs2: the second list of element/attribute defs
3836 *
3837 * Compare the 2 lists of element or attribute definitions. The comparison
3838 * is that if both lists do not accept the same QNames, it returns 1
3839 * If the 2 lists can accept the same QName the comparison returns 0
3840 *
3841 * Returns 1 disttinct, 0 if equal
3842 */
3843static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003844xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3845 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3846 xmlRelaxNGDefinePtr * def2)
3847{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003848 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003849
Daniel Veillard154877e2003-01-30 12:17:05 +00003850 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003851 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003852 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003853 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003854 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003855 while ((*def2) != NULL) {
3856 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3857 return (0);
3858 def2++;
3859 }
3860 def2 = basedef2;
3861 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003862 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003863 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003864}
3865
3866/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003867 * xmlRelaxNGGenerateAttributes:
3868 * @ctxt: a Relax-NG parser context
3869 * @def: the definition definition
3870 *
3871 * Check if the definition can only generate attributes
3872 *
3873 * Returns 1 if yes, 0 if no and -1 in case of error.
3874 */
3875static int
3876xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003877 xmlRelaxNGDefinePtr def)
3878{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003879 xmlRelaxNGDefinePtr parent, cur, tmp;
3880
3881 /*
3882 * Don't run that check in case of error. Infinite recursion
3883 * becomes possible.
3884 */
3885 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003886 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003887
3888 parent = NULL;
3889 cur = def;
3890 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003891 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3892 (cur->type == XML_RELAXNG_TEXT) ||
3893 (cur->type == XML_RELAXNG_DATATYPE) ||
3894 (cur->type == XML_RELAXNG_PARAM) ||
3895 (cur->type == XML_RELAXNG_LIST) ||
3896 (cur->type == XML_RELAXNG_VALUE) ||
3897 (cur->type == XML_RELAXNG_EMPTY))
3898 return (0);
3899 if ((cur->type == XML_RELAXNG_CHOICE) ||
3900 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3901 (cur->type == XML_RELAXNG_GROUP) ||
3902 (cur->type == XML_RELAXNG_ONEORMORE) ||
3903 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3904 (cur->type == XML_RELAXNG_OPTIONAL) ||
3905 (cur->type == XML_RELAXNG_PARENTREF) ||
3906 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3907 (cur->type == XML_RELAXNG_REF) ||
3908 (cur->type == XML_RELAXNG_DEF)) {
3909 if (cur->content != NULL) {
3910 parent = cur;
3911 cur = cur->content;
3912 tmp = cur;
3913 while (tmp != NULL) {
3914 tmp->parent = parent;
3915 tmp = tmp->next;
3916 }
3917 continue;
3918 }
3919 }
3920 if (cur == def)
3921 break;
3922 if (cur->next != NULL) {
3923 cur = cur->next;
3924 continue;
3925 }
3926 do {
3927 cur = cur->parent;
3928 if (cur == NULL)
3929 break;
3930 if (cur == def)
3931 return (1);
3932 if (cur->next != NULL) {
3933 cur = cur->next;
3934 break;
3935 }
3936 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003937 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003938 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003939}
Daniel Veillard4c004142003-10-07 11:33:24 +00003940
Daniel Veillardce192eb2003-04-16 15:58:05 +00003941/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003942 * xmlRelaxNGGetElements:
3943 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003944 * @def: the definition definition
3945 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003946 *
3947 * Compute the list of top elements a definition can generate
3948 *
3949 * Returns a list of elements or NULL if none was found.
3950 */
3951static xmlRelaxNGDefinePtr *
3952xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003953 xmlRelaxNGDefinePtr def, int eora)
3954{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003955 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003956 int len = 0;
3957 int max = 0;
3958
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003959 /*
3960 * Don't run that check in case of error. Infinite recursion
3961 * becomes possible.
3962 */
3963 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003964 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003965
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003966 parent = NULL;
3967 cur = def;
3968 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003969 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3970 (cur->type == XML_RELAXNG_TEXT))) ||
3971 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3972 if (ret == NULL) {
3973 max = 10;
3974 ret = (xmlRelaxNGDefinePtr *)
3975 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3976 if (ret == NULL) {
3977 xmlRngPErrMemory(ctxt, "getting element list\n");
3978 return (NULL);
3979 }
3980 } else if (max <= len) {
Daniel Veillard079f6a72004-09-23 13:15:03 +00003981 xmlRelaxNGDefinePtr *temp;
3982
Daniel Veillard4c004142003-10-07 11:33:24 +00003983 max *= 2;
Daniel Veillard079f6a72004-09-23 13:15:03 +00003984 temp = xmlRealloc(ret,
Daniel Veillard4c004142003-10-07 11:33:24 +00003985 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
Daniel Veillard079f6a72004-09-23 13:15:03 +00003986 if (temp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003987 xmlRngPErrMemory(ctxt, "getting element list\n");
Daniel Veillard079f6a72004-09-23 13:15:03 +00003988 xmlFree(ret);
Daniel Veillard4c004142003-10-07 11:33:24 +00003989 return (NULL);
3990 }
Daniel Veillard079f6a72004-09-23 13:15:03 +00003991 ret = temp;
Daniel Veillard4c004142003-10-07 11:33:24 +00003992 }
3993 ret[len++] = cur;
3994 ret[len] = NULL;
3995 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3996 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3997 (cur->type == XML_RELAXNG_GROUP) ||
3998 (cur->type == XML_RELAXNG_ONEORMORE) ||
3999 (cur->type == XML_RELAXNG_ZEROORMORE) ||
4000 (cur->type == XML_RELAXNG_OPTIONAL) ||
4001 (cur->type == XML_RELAXNG_PARENTREF) ||
4002 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00004003 (cur->type == XML_RELAXNG_DEF) ||
4004 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004005 /*
4006 * Don't go within elements or attributes or string values.
4007 * Just gather the element top list
4008 */
4009 if (cur->content != NULL) {
4010 parent = cur;
4011 cur = cur->content;
4012 tmp = cur;
4013 while (tmp != NULL) {
4014 tmp->parent = parent;
4015 tmp = tmp->next;
4016 }
4017 continue;
4018 }
4019 }
4020 if (cur == def)
4021 break;
4022 if (cur->next != NULL) {
4023 cur = cur->next;
4024 continue;
4025 }
4026 do {
4027 cur = cur->parent;
4028 if (cur == NULL)
4029 break;
4030 if (cur == def)
4031 return (ret);
4032 if (cur->next != NULL) {
4033 cur = cur->next;
4034 break;
4035 }
4036 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004037 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004038 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004039}
Daniel Veillard4c004142003-10-07 11:33:24 +00004040
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004041/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004042 * xmlRelaxNGCheckChoiceDeterminism:
4043 * @ctxt: a Relax-NG parser context
4044 * @def: the choice definition
4045 *
4046 * Also used to find indeterministic pattern in choice
4047 */
4048static void
4049xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004050 xmlRelaxNGDefinePtr def)
4051{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004052 xmlRelaxNGDefinePtr **list;
4053 xmlRelaxNGDefinePtr cur;
4054 int nbchild = 0, i, j, ret;
4055 int is_nullable = 0;
4056 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004057 xmlHashTablePtr triage = NULL;
4058 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004059
Daniel Veillard4c004142003-10-07 11:33:24 +00004060 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4061 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004062
Daniel Veillarde063f482003-03-21 16:53:17 +00004063 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004064 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004065
Daniel Veillardfd573f12003-03-16 17:52:32 +00004066 /*
4067 * Don't run that check in case of error. Infinite recursion
4068 * becomes possible.
4069 */
4070 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004071 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004072
4073 is_nullable = xmlRelaxNGIsNullable(def);
4074
4075 cur = def->content;
4076 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004077 nbchild++;
4078 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004079 }
4080
4081 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004082 sizeof(xmlRelaxNGDefinePtr
4083 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004084 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004085 xmlRngPErrMemory(ctxt, "building choice\n");
4086 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004087 }
4088 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004089 /*
4090 * a bit strong but safe
4091 */
4092 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004093 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004094 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004095 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004096 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004097 cur = def->content;
4098 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004099 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4100 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4101 is_triable = 0;
4102 } else if (is_triable == 1) {
4103 xmlRelaxNGDefinePtr *tmp;
4104 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004105
Daniel Veillard4c004142003-10-07 11:33:24 +00004106 tmp = list[i];
4107 while ((*tmp != NULL) && (is_triable == 1)) {
4108 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4109 res = xmlHashAddEntry2(triage,
4110 BAD_CAST "#text", NULL,
4111 (void *) cur);
4112 if (res != 0)
4113 is_triable = -1;
4114 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4115 ((*tmp)->name != NULL)) {
4116 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4117 res = xmlHashAddEntry2(triage,
4118 (*tmp)->name, NULL,
4119 (void *) cur);
4120 else
4121 res = xmlHashAddEntry2(triage,
4122 (*tmp)->name, (*tmp)->ns,
4123 (void *) cur);
4124 if (res != 0)
4125 is_triable = -1;
4126 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4127 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4128 res = xmlHashAddEntry2(triage,
4129 BAD_CAST "#any", NULL,
4130 (void *) cur);
4131 else
4132 res = xmlHashAddEntry2(triage,
4133 BAD_CAST "#any", (*tmp)->ns,
4134 (void *) cur);
4135 if (res != 0)
4136 is_triable = -1;
4137 } else {
4138 is_triable = -1;
4139 }
4140 tmp++;
4141 }
4142 }
4143 i++;
4144 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004145 }
4146
Daniel Veillard4c004142003-10-07 11:33:24 +00004147 for (i = 0; i < nbchild; i++) {
4148 if (list[i] == NULL)
4149 continue;
4150 for (j = 0; j < i; j++) {
4151 if (list[j] == NULL)
4152 continue;
4153 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4154 if (ret == 0) {
4155 is_indeterminist = 1;
4156 }
4157 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004158 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004159 for (i = 0; i < nbchild; i++) {
4160 if (list[i] != NULL)
4161 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162 }
4163
4164 xmlFree(list);
4165 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004166 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004167 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004168 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004169 def->dflags |= IS_TRIABLE;
4170 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004171 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004172 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004173 }
4174 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004175}
4176
4177/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004178 * xmlRelaxNGCheckGroupAttrs:
4179 * @ctxt: a Relax-NG parser context
4180 * @def: the group definition
4181 *
4182 * Detects violations of rule 7.3
4183 */
4184static void
4185xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004186 xmlRelaxNGDefinePtr def)
4187{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004188 xmlRelaxNGDefinePtr **list;
4189 xmlRelaxNGDefinePtr cur;
4190 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004191
4192 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004193 ((def->type != XML_RELAXNG_GROUP) &&
4194 (def->type != XML_RELAXNG_ELEMENT)))
4195 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004196
Daniel Veillarde063f482003-03-21 16:53:17 +00004197 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004198 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004199
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004200 /*
4201 * Don't run that check in case of error. Infinite recursion
4202 * becomes possible.
4203 */
4204 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004205 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004206
Daniel Veillardfd573f12003-03-16 17:52:32 +00004207 cur = def->attrs;
4208 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004209 nbchild++;
4210 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004211 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004212 cur = def->content;
4213 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004214 nbchild++;
4215 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004216 }
4217
4218 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004219 sizeof(xmlRelaxNGDefinePtr
4220 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004221 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004222 xmlRngPErrMemory(ctxt, "building group\n");
4223 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004224 }
4225 i = 0;
4226 cur = def->attrs;
4227 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004228 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4229 i++;
4230 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004231 }
4232 cur = def->content;
4233 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004234 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4235 i++;
4236 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004237 }
4238
Daniel Veillard4c004142003-10-07 11:33:24 +00004239 for (i = 0; i < nbchild; i++) {
4240 if (list[i] == NULL)
4241 continue;
4242 for (j = 0; j < i; j++) {
4243 if (list[j] == NULL)
4244 continue;
4245 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4246 if (ret == 0) {
4247 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4248 "Attributes conflicts in group\n", NULL, NULL);
4249 }
4250 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004251 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004252 for (i = 0; i < nbchild; i++) {
4253 if (list[i] != NULL)
4254 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004255 }
4256
4257 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004258 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004259}
4260
4261/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004262 * xmlRelaxNGComputeInterleaves:
4263 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004264 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004265 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004266 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004267 * A lot of work for preprocessing interleave definitions
4268 * is potentially needed to get a decent execution speed at runtime
4269 * - trying to get a total order on the element nodes generated
4270 * by the interleaves, order the list of interleave definitions
4271 * following that order.
4272 * - if <text/> is used to handle mixed content, it is better to
4273 * flag this in the define and simplify the runtime checking
4274 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004275 */
4276static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004277xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004278 xmlRelaxNGParserCtxtPtr ctxt,
4279 xmlChar * name ATTRIBUTE_UNUSED)
4280{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004281 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004282
Daniel Veillardfd573f12003-03-16 17:52:32 +00004283 xmlRelaxNGPartitionPtr partitions = NULL;
4284 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4285 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004286 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004287 int nbgroups = 0;
4288 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004289 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004290 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004291
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004292 /*
4293 * Don't run that check in case of error. Infinite recursion
4294 * becomes possible.
4295 */
4296 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004297 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004298
Daniel Veillardfd573f12003-03-16 17:52:32 +00004299#ifdef DEBUG_INTERLEAVE
4300 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004301 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004302#endif
4303 cur = def->content;
4304 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004305 nbchild++;
4306 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004307 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004308
Daniel Veillardfd573f12003-03-16 17:52:32 +00004309#ifdef DEBUG_INTERLEAVE
4310 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4311#endif
4312 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004313 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004314 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004315 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004316 cur = def->content;
4317 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004318 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4319 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4320 if (groups[nbgroups] == NULL)
4321 goto error;
4322 if (cur->type == XML_RELAXNG_TEXT)
4323 is_mixed++;
4324 groups[nbgroups]->rule = cur;
4325 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4326 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4327 nbgroups++;
4328 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004329 }
4330#ifdef DEBUG_INTERLEAVE
4331 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4332#endif
4333
4334 /*
4335 * Let's check that all rules makes a partitions according to 7.4
4336 */
4337 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004338 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004339 if (partitions == NULL)
4340 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004341 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004342 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004343 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004344 for (i = 0; i < nbgroups; i++) {
4345 group = groups[i];
4346 for (j = i + 1; j < nbgroups; j++) {
4347 if (groups[j] == NULL)
4348 continue;
4349
4350 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4351 groups[j]->defs);
4352 if (ret == 0) {
4353 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4354 "Element or text conflicts in interleave\n",
4355 NULL, NULL);
4356 }
4357 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4358 groups[j]->attrs);
4359 if (ret == 0) {
4360 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4361 "Attributes conflicts in interleave\n", NULL,
4362 NULL);
4363 }
4364 }
4365 tmp = group->defs;
4366 if ((tmp != NULL) && (*tmp != NULL)) {
4367 while (*tmp != NULL) {
4368 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4369 res = xmlHashAddEntry2(partitions->triage,
4370 BAD_CAST "#text", NULL,
4371 (void *) (long) (i + 1));
4372 if (res != 0)
4373 is_determinist = -1;
4374 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4375 ((*tmp)->name != NULL)) {
4376 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4377 res = xmlHashAddEntry2(partitions->triage,
4378 (*tmp)->name, NULL,
4379 (void *) (long) (i + 1));
4380 else
4381 res = xmlHashAddEntry2(partitions->triage,
4382 (*tmp)->name, (*tmp)->ns,
4383 (void *) (long) (i + 1));
4384 if (res != 0)
4385 is_determinist = -1;
4386 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4387 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4388 res = xmlHashAddEntry2(partitions->triage,
4389 BAD_CAST "#any", NULL,
4390 (void *) (long) (i + 1));
4391 else
4392 res = xmlHashAddEntry2(partitions->triage,
4393 BAD_CAST "#any", (*tmp)->ns,
4394 (void *) (long) (i + 1));
4395 if ((*tmp)->nameClass != NULL)
4396 is_determinist = 2;
4397 if (res != 0)
4398 is_determinist = -1;
4399 } else {
4400 is_determinist = -1;
4401 }
4402 tmp++;
4403 }
4404 } else {
4405 is_determinist = 0;
4406 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004407 }
4408 partitions->groups = groups;
4409
4410 /*
4411 * and save the partition list back in the def
4412 */
4413 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004414 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004415 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004416 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004417 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004418 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004419 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004420 return;
4421
Daniel Veillard4c004142003-10-07 11:33:24 +00004422 error:
4423 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004424 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004425 for (i = 0; i < nbgroups; i++)
4426 if (groups[i] != NULL) {
4427 if (groups[i]->defs != NULL)
4428 xmlFree(groups[i]->defs);
4429 xmlFree(groups[i]);
4430 }
4431 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004432 }
4433 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004434}
4435
4436/**
4437 * xmlRelaxNGParseInterleave:
4438 * @ctxt: a Relax-NG parser context
4439 * @node: the data node.
4440 *
4441 * parse the content of a RelaxNG interleave node.
4442 *
4443 * Returns the definition pointer or NULL in case of error
4444 */
4445static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004446xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4447{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004448 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004449 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004450 xmlNodePtr child;
4451
Daniel Veillardfd573f12003-03-16 17:52:32 +00004452 def = xmlRelaxNGNewDefine(ctxt, node);
4453 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004454 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004455 }
4456 def->type = XML_RELAXNG_INTERLEAVE;
4457
4458 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004459 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004460 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004461 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004462 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004463 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004464
Daniel Veillard4c004142003-10-07 11:33:24 +00004465 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4466 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4467 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4468 "Failed to add %s to hash table\n",
4469 (const xmlChar *) name, NULL);
4470 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004471 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004472 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004473 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004474 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4475 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004476 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004477 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004478 if (IS_RELAXNG(child, "element")) {
4479 cur = xmlRelaxNGParseElement(ctxt, child);
4480 } else {
4481 cur = xmlRelaxNGParsePattern(ctxt, child);
4482 }
4483 if (cur != NULL) {
4484 cur->parent = def;
4485 if (last == NULL) {
4486 def->content = last = cur;
4487 } else {
4488 last->next = cur;
4489 last = cur;
4490 }
4491 }
4492 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004493 }
4494
Daniel Veillard4c004142003-10-07 11:33:24 +00004495 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004496}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004497
4498/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004499 * xmlRelaxNGParseInclude:
4500 * @ctxt: a Relax-NG parser context
4501 * @node: the include node
4502 *
4503 * Integrate the content of an include node in the current grammar
4504 *
4505 * Returns 0 in case of success or -1 in case of error
4506 */
4507static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004508xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4509{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004510 xmlRelaxNGIncludePtr incl;
4511 xmlNodePtr root;
4512 int ret = 0, tmp;
4513
Daniel Veillard807daf82004-02-22 22:13:27 +00004514 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004515 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004516 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4517 "Include node has no data\n", NULL, NULL);
4518 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004519 }
4520 root = xmlDocGetRootElement(incl->doc);
4521 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004522 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4523 NULL, NULL);
4524 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004525 }
4526 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004527 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4528 "Include document root is not a grammar\n", NULL, NULL);
4529 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004530 }
4531
4532 /*
4533 * Merge the definition from both the include and the internal list
4534 */
4535 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004536 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4537 if (tmp != 0)
4538 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004539 }
4540 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004541 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4542 if (tmp != 0)
4543 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004544 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004545 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004546}
4547
4548/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004549 * xmlRelaxNGParseDefine:
4550 * @ctxt: a Relax-NG parser context
4551 * @node: the define node
4552 *
4553 * parse the content of a RelaxNG define element node.
4554 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004555 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004556 */
4557static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004558xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4559{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004560 xmlChar *name;
4561 int ret = 0, tmp;
4562 xmlRelaxNGDefinePtr def;
4563 const xmlChar *olddefine;
4564
4565 name = xmlGetProp(node, BAD_CAST "name");
4566 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004567 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4568 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004569 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004570 xmlRelaxNGNormExtSpace(name);
4571 if (xmlValidateNCName(name, 0)) {
4572 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4573 "define name '%s' is not an NCName\n", name, NULL);
4574 }
4575 def = xmlRelaxNGNewDefine(ctxt, node);
4576 if (def == NULL) {
4577 xmlFree(name);
4578 return (-1);
4579 }
4580 def->type = XML_RELAXNG_DEF;
4581 def->name = name;
4582 if (node->children == NULL) {
4583 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4584 "define has no children\n", NULL, NULL);
4585 } else {
4586 olddefine = ctxt->define;
4587 ctxt->define = name;
4588 def->content =
4589 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4590 ctxt->define = olddefine;
4591 }
4592 if (ctxt->grammar->defs == NULL)
4593 ctxt->grammar->defs = xmlHashCreate(10);
4594 if (ctxt->grammar->defs == NULL) {
4595 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4596 "Could not create definition hash\n", NULL, NULL);
4597 ret = -1;
4598 } else {
4599 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4600 if (tmp < 0) {
4601 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004602
Daniel Veillard4c004142003-10-07 11:33:24 +00004603 prev = xmlHashLookup(ctxt->grammar->defs, name);
4604 if (prev == NULL) {
4605 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4606 "Internal error on define aggregation of %s\n",
4607 name, NULL);
4608 ret = -1;
4609 } else {
4610 while (prev->nextHash != NULL)
4611 prev = prev->nextHash;
4612 prev->nextHash = def;
4613 }
4614 }
4615 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004616 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004617 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004618}
4619
4620/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004621 * xmlRelaxNGProcessExternalRef:
4622 * @ctxt: the parser context
4623 * @node: the externlRef node
4624 *
4625 * Process and compile an externlRef node
4626 *
4627 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4628 */
4629static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004630xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4631{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004632 xmlRelaxNGDocumentPtr docu;
4633 xmlNodePtr root, tmp;
4634 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004635 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004636 xmlRelaxNGDefinePtr def;
4637
Daniel Veillard807daf82004-02-22 22:13:27 +00004638 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004639 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004640 def = xmlRelaxNGNewDefine(ctxt, node);
4641 if (def == NULL)
4642 return (NULL);
4643 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004644
Daniel Veillard4c004142003-10-07 11:33:24 +00004645 if (docu->content == NULL) {
4646 /*
4647 * Then do the parsing for good
4648 */
4649 root = xmlDocGetRootElement(docu->doc);
4650 if (root == NULL) {
4651 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4652 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4653 NULL);
4654 return (NULL);
4655 }
4656 /*
4657 * ns transmission rules
4658 */
4659 ns = xmlGetProp(root, BAD_CAST "ns");
4660 if (ns == NULL) {
4661 tmp = node;
4662 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4663 ns = xmlGetProp(tmp, BAD_CAST "ns");
4664 if (ns != NULL) {
4665 break;
4666 }
4667 tmp = tmp->parent;
4668 }
4669 if (ns != NULL) {
4670 xmlSetProp(root, BAD_CAST "ns", ns);
4671 newNs = 1;
4672 xmlFree(ns);
4673 }
4674 } else {
4675 xmlFree(ns);
4676 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004677
Daniel Veillard4c004142003-10-07 11:33:24 +00004678 /*
4679 * Parsing to get a precompiled schemas.
4680 */
4681 oldflags = ctxt->flags;
4682 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4683 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4684 ctxt->flags = oldflags;
4685 if ((docu->schema != NULL) &&
4686 (docu->schema->topgrammar != NULL)) {
4687 docu->content = docu->schema->topgrammar->start;
4688 }
4689
4690 /*
4691 * the externalRef may be reused in a different ns context
4692 */
4693 if (newNs == 1) {
4694 xmlUnsetProp(root, BAD_CAST "ns");
4695 }
4696 }
4697 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004698 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004699 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004700 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004701 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004702}
4703
4704/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004705 * xmlRelaxNGParsePattern:
4706 * @ctxt: a Relax-NG parser context
4707 * @node: the pattern node.
4708 *
4709 * parse the content of a RelaxNG pattern node.
4710 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004711 * Returns the definition pointer or NULL in case of error or if no
4712 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004713 */
4714static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004715xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4716{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004717 xmlRelaxNGDefinePtr def = NULL;
4718
Daniel Veillardd2298792003-02-14 16:54:11 +00004719 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004720 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004721 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004722 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004723 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004724 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004725 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004726 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004727 def = xmlRelaxNGNewDefine(ctxt, node);
4728 if (def == NULL)
4729 return (NULL);
4730 def->type = XML_RELAXNG_EMPTY;
4731 if (node->children != NULL) {
4732 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4733 "empty: had a child node\n", NULL, NULL);
4734 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004735 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004736 def = xmlRelaxNGNewDefine(ctxt, node);
4737 if (def == NULL)
4738 return (NULL);
4739 def->type = XML_RELAXNG_TEXT;
4740 if (node->children != NULL) {
4741 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4742 "text: had a child node\n", NULL, NULL);
4743 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004744 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004745 def = xmlRelaxNGNewDefine(ctxt, node);
4746 if (def == NULL)
4747 return (NULL);
4748 def->type = XML_RELAXNG_ZEROORMORE;
4749 if (node->children == NULL) {
4750 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4751 "Element %s is empty\n", node->name, NULL);
4752 } else {
4753 def->content =
4754 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4755 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004756 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004757 def = xmlRelaxNGNewDefine(ctxt, node);
4758 if (def == NULL)
4759 return (NULL);
4760 def->type = XML_RELAXNG_ONEORMORE;
4761 if (node->children == NULL) {
4762 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4763 "Element %s is empty\n", node->name, NULL);
4764 } else {
4765 def->content =
4766 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4767 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004768 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004769 def = xmlRelaxNGNewDefine(ctxt, node);
4770 if (def == NULL)
4771 return (NULL);
4772 def->type = XML_RELAXNG_OPTIONAL;
4773 if (node->children == NULL) {
4774 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4775 "Element %s is empty\n", node->name, NULL);
4776 } else {
4777 def->content =
4778 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4779 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004780 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004781 def = xmlRelaxNGNewDefine(ctxt, node);
4782 if (def == NULL)
4783 return (NULL);
4784 def->type = XML_RELAXNG_CHOICE;
4785 if (node->children == NULL) {
4786 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4787 "Element %s is empty\n", node->name, NULL);
4788 } else {
4789 def->content =
4790 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4791 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004792 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004793 def = xmlRelaxNGNewDefine(ctxt, node);
4794 if (def == NULL)
4795 return (NULL);
4796 def->type = XML_RELAXNG_GROUP;
4797 if (node->children == NULL) {
4798 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4799 "Element %s is empty\n", node->name, NULL);
4800 } else {
4801 def->content =
4802 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4803 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004804 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004805 def = xmlRelaxNGNewDefine(ctxt, node);
4806 if (def == NULL)
4807 return (NULL);
4808 def->type = XML_RELAXNG_REF;
4809 def->name = xmlGetProp(node, BAD_CAST "name");
4810 if (def->name == NULL) {
4811 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4812 NULL, NULL);
4813 } else {
4814 xmlRelaxNGNormExtSpace(def->name);
4815 if (xmlValidateNCName(def->name, 0)) {
4816 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4817 "ref name '%s' is not an NCName\n", def->name,
4818 NULL);
4819 }
4820 }
4821 if (node->children != NULL) {
4822 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4823 NULL, NULL);
4824 }
4825 if (ctxt->grammar->refs == NULL)
4826 ctxt->grammar->refs = xmlHashCreate(10);
4827 if (ctxt->grammar->refs == NULL) {
4828 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4829 "Could not create references hash\n", NULL, NULL);
4830 def = NULL;
4831 } else {
4832 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004833
Daniel Veillard4c004142003-10-07 11:33:24 +00004834 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4835 if (tmp < 0) {
4836 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004837
Daniel Veillard4c004142003-10-07 11:33:24 +00004838 prev = (xmlRelaxNGDefinePtr)
4839 xmlHashLookup(ctxt->grammar->refs, def->name);
4840 if (prev == NULL) {
4841 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004842 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4843 "Error refs definitions '%s'\n",
4844 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004845 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004846 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4847 "Error refs definitions\n",
4848 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004849 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004850 def = NULL;
4851 } else {
4852 def->nextHash = prev->nextHash;
4853 prev->nextHash = def;
4854 }
4855 }
4856 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004857 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004858 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004859 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004860 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004861 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004862 def = xmlRelaxNGNewDefine(ctxt, node);
4863 if (def == NULL)
4864 return (NULL);
4865 def->type = XML_RELAXNG_LIST;
4866 if (node->children == NULL) {
4867 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4868 "Element %s is empty\n", node->name, NULL);
4869 } else {
4870 def->content =
4871 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4872 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004873 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004874 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004875 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004876 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004877 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004878 def = xmlRelaxNGNewDefine(ctxt, node);
4879 if (def == NULL)
4880 return (NULL);
4881 def->type = XML_RELAXNG_NOT_ALLOWED;
4882 if (node->children != NULL) {
4883 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4884 "xmlRelaxNGParse: notAllowed element is not empty\n",
4885 NULL, NULL);
4886 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004887 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004888 xmlRelaxNGGrammarPtr grammar, old;
4889 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004890
Daniel Veillardc482e262003-02-26 14:48:48 +00004891#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004892 xmlGenericError(xmlGenericErrorContext,
4893 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004894#endif
4895
Daniel Veillard4c004142003-10-07 11:33:24 +00004896 oldparent = ctxt->parentgrammar;
4897 old = ctxt->grammar;
4898 ctxt->parentgrammar = old;
4899 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4900 if (old != NULL) {
4901 ctxt->grammar = old;
4902 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004903#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004904 if (grammar != NULL) {
4905 grammar->next = old->next;
4906 old->next = grammar;
4907 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004908#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004909 }
4910 if (grammar != NULL)
4911 def = grammar->start;
4912 else
4913 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004914 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004915 if (ctxt->parentgrammar == NULL) {
4916 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4917 "Use of parentRef without a parent grammar\n", NULL,
4918 NULL);
4919 return (NULL);
4920 }
4921 def = xmlRelaxNGNewDefine(ctxt, node);
4922 if (def == NULL)
4923 return (NULL);
4924 def->type = XML_RELAXNG_PARENTREF;
4925 def->name = xmlGetProp(node, BAD_CAST "name");
4926 if (def->name == NULL) {
4927 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4928 "parentRef has no name\n", NULL, NULL);
4929 } else {
4930 xmlRelaxNGNormExtSpace(def->name);
4931 if (xmlValidateNCName(def->name, 0)) {
4932 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4933 "parentRef name '%s' is not an NCName\n",
4934 def->name, NULL);
4935 }
4936 }
4937 if (node->children != NULL) {
4938 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4939 "parentRef is not empty\n", NULL, NULL);
4940 }
4941 if (ctxt->parentgrammar->refs == NULL)
4942 ctxt->parentgrammar->refs = xmlHashCreate(10);
4943 if (ctxt->parentgrammar->refs == NULL) {
4944 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4945 "Could not create references hash\n", NULL, NULL);
4946 def = NULL;
4947 } else if (def->name != NULL) {
4948 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004949
Daniel Veillard4c004142003-10-07 11:33:24 +00004950 tmp =
4951 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4952 if (tmp < 0) {
4953 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004954
Daniel Veillard4c004142003-10-07 11:33:24 +00004955 prev = (xmlRelaxNGDefinePtr)
4956 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4957 if (prev == NULL) {
4958 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4959 "Internal error parentRef definitions '%s'\n",
4960 def->name, NULL);
4961 def = NULL;
4962 } else {
4963 def->nextHash = prev->nextHash;
4964 prev->nextHash = def;
4965 }
4966 }
4967 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004968 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004969 if (node->children == NULL) {
4970 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4971 NULL, NULL);
4972 def = NULL;
4973 } else {
4974 def = xmlRelaxNGParseInterleave(ctxt, node);
4975 if (def != NULL) {
4976 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004977
Daniel Veillard4c004142003-10-07 11:33:24 +00004978 if ((def->content != NULL) && (def->content->next != NULL)) {
4979 tmp = xmlRelaxNGNewDefine(ctxt, node);
4980 if (tmp != NULL) {
4981 tmp->type = XML_RELAXNG_GROUP;
4982 tmp->content = def->content;
4983 def->content = tmp;
4984 }
4985 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004986
Daniel Veillard4c004142003-10-07 11:33:24 +00004987 tmp = xmlRelaxNGNewDefine(ctxt, node);
4988 if (tmp == NULL)
4989 return (def);
4990 tmp->type = XML_RELAXNG_TEXT;
4991 tmp->next = def->content;
4992 def->content = tmp;
4993 }
4994 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004995 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004996 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4997 "Unexpected node %s is not a pattern\n", node->name,
4998 NULL);
4999 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005000 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005001 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005002}
5003
5004/**
5005 * xmlRelaxNGParseAttribute:
5006 * @ctxt: a Relax-NG parser context
5007 * @node: the element node
5008 *
5009 * parse the content of a RelaxNG attribute node.
5010 *
5011 * Returns the definition pointer or NULL in case of error.
5012 */
5013static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005014xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5015{
Daniel Veillardd2298792003-02-14 16:54:11 +00005016 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005017 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005018 int old_flags;
5019
Daniel Veillardfd573f12003-03-16 17:52:32 +00005020 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005021 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005022 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005023 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005024 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005025 child = node->children;
5026 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005027 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5028 "xmlRelaxNGParseattribute: attribute has no children\n",
5029 NULL, NULL);
5030 return (ret);
5031 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005032 old_flags = ctxt->flags;
5033 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005034 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5035 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005036 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005037
Daniel Veillardd2298792003-02-14 16:54:11 +00005038 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005039 cur = xmlRelaxNGParsePattern(ctxt, child);
5040 if (cur != NULL) {
5041 switch (cur->type) {
5042 case XML_RELAXNG_EMPTY:
5043 case XML_RELAXNG_NOT_ALLOWED:
5044 case XML_RELAXNG_TEXT:
5045 case XML_RELAXNG_ELEMENT:
5046 case XML_RELAXNG_DATATYPE:
5047 case XML_RELAXNG_VALUE:
5048 case XML_RELAXNG_LIST:
5049 case XML_RELAXNG_REF:
5050 case XML_RELAXNG_PARENTREF:
5051 case XML_RELAXNG_EXTERNALREF:
5052 case XML_RELAXNG_DEF:
5053 case XML_RELAXNG_ONEORMORE:
5054 case XML_RELAXNG_ZEROORMORE:
5055 case XML_RELAXNG_OPTIONAL:
5056 case XML_RELAXNG_CHOICE:
5057 case XML_RELAXNG_GROUP:
5058 case XML_RELAXNG_INTERLEAVE:
5059 case XML_RELAXNG_ATTRIBUTE:
5060 ret->content = cur;
5061 cur->parent = ret;
5062 break;
5063 case XML_RELAXNG_START:
5064 case XML_RELAXNG_PARAM:
5065 case XML_RELAXNG_EXCEPT:
5066 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5067 "attribute has invalid content\n", NULL,
5068 NULL);
5069 break;
5070 case XML_RELAXNG_NOOP:
5071 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5072 "RNG Internal error, noop found in attribute\n",
5073 NULL, NULL);
5074 break;
5075 }
5076 }
5077 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005078 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005079 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005080 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5081 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005082 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005083 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005084 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005085}
5086
5087/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005088 * xmlRelaxNGParseExceptNameClass:
5089 * @ctxt: a Relax-NG parser context
5090 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005091 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005092 *
5093 * parse the content of a RelaxNG nameClass node.
5094 *
5095 * Returns the definition pointer or NULL in case of error.
5096 */
5097static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005098xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005099 xmlNodePtr node, int attr)
5100{
Daniel Veillard144fae12003-02-03 13:17:57 +00005101 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5102 xmlNodePtr child;
5103
Daniel Veillardd2298792003-02-14 16:54:11 +00005104 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005105 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5106 "Expecting an except node\n", NULL, NULL);
5107 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005108 }
5109 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005110 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5111 "exceptNameClass allows only a single except node\n",
5112 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005113 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005114 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005115 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5116 NULL, NULL);
5117 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005118 }
5119
Daniel Veillardfd573f12003-03-16 17:52:32 +00005120 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005121 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005122 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005123 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005124 child = node->children;
5125 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005126 cur = xmlRelaxNGNewDefine(ctxt, child);
5127 if (cur == NULL)
5128 break;
5129 if (attr)
5130 cur->type = XML_RELAXNG_ATTRIBUTE;
5131 else
5132 cur->type = XML_RELAXNG_ELEMENT;
5133
Daniel Veillard419a7682003-02-03 23:22:49 +00005134 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005135 if (last == NULL) {
5136 ret->content = cur;
5137 } else {
5138 last->next = cur;
5139 }
5140 last = cur;
5141 }
5142 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005143 }
5144
Daniel Veillard4c004142003-10-07 11:33:24 +00005145 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005146}
5147
5148/**
5149 * xmlRelaxNGParseNameClass:
5150 * @ctxt: a Relax-NG parser context
5151 * @node: the nameClass node
5152 * @def: the current definition
5153 *
5154 * parse the content of a RelaxNG nameClass node.
5155 *
5156 * Returns the definition pointer or NULL in case of error.
5157 */
5158static xmlRelaxNGDefinePtr
5159xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005160 xmlRelaxNGDefinePtr def)
5161{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005162 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005163 xmlChar *val;
5164
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005165 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005166 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005167 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005168 if ((def->type != XML_RELAXNG_ELEMENT) &&
5169 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5170 ret = xmlRelaxNGNewDefine(ctxt, node);
5171 if (ret == NULL)
5172 return (NULL);
5173 ret->parent = def;
5174 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5175 ret->type = XML_RELAXNG_ATTRIBUTE;
5176 else
5177 ret->type = XML_RELAXNG_ELEMENT;
5178 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005179 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005180 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005181 val = xmlNodeGetContent(node);
5182 xmlRelaxNGNormExtSpace(val);
5183 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005184 if (node->parent != NULL)
5185 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5186 "Element %s name '%s' is not an NCName\n",
5187 node->parent->name, val);
5188 else
5189 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5190 "name '%s' is not an NCName\n",
5191 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005192 }
5193 ret->name = val;
5194 val = xmlGetProp(node, BAD_CAST "ns");
5195 ret->ns = val;
5196 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5197 (val != NULL) &&
5198 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005199 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005200 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005201 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005202 }
5203 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5204 (val != NULL) &&
5205 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005206 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5207 "Attribute with QName 'xmlns' is not allowed\n",
5208 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005209 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005210 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005211 ret->name = NULL;
5212 ret->ns = NULL;
5213 if (node->children != NULL) {
5214 ret->nameClass =
5215 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5216 (def->type ==
5217 XML_RELAXNG_ATTRIBUTE));
5218 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005219 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005220 ret->name = NULL;
5221 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5222 if (ret->ns == NULL) {
5223 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5224 "nsName has no ns attribute\n", NULL, NULL);
5225 }
5226 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5227 (ret->ns != NULL) &&
5228 (xmlStrEqual
5229 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5230 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5231 "Attribute with namespace '%s' is not allowed\n",
5232 ret->ns, NULL);
5233 }
5234 if (node->children != NULL) {
5235 ret->nameClass =
5236 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5237 (def->type ==
5238 XML_RELAXNG_ATTRIBUTE));
5239 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005240 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005241 xmlNodePtr child;
5242 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005243
Daniel Veillard4c004142003-10-07 11:33:24 +00005244 ret = xmlRelaxNGNewDefine(ctxt, node);
5245 if (ret == NULL)
5246 return (NULL);
5247 ret->parent = def;
5248 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005249
Daniel Veillard4c004142003-10-07 11:33:24 +00005250 if (node->children == NULL) {
5251 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5252 "Element choice is empty\n", NULL, NULL);
5253 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005254
Daniel Veillard4c004142003-10-07 11:33:24 +00005255 child = node->children;
5256 while (child != NULL) {
5257 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5258 if (tmp != NULL) {
5259 if (last == NULL) {
5260 last = ret->nameClass = tmp;
5261 } else {
5262 last->next = tmp;
5263 last = tmp;
5264 }
5265 }
5266 child = child->next;
5267 }
5268 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005269 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005270 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5271 "expecting name, anyName, nsName or choice : got %s\n",
5272 node->name, NULL);
5273 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005274 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005275 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005276 if (def->nameClass == NULL) {
5277 def->nameClass = ret;
5278 } else {
5279 tmp = def->nameClass;
5280 while (tmp->next != NULL) {
5281 tmp = tmp->next;
5282 }
5283 tmp->next = ret;
5284 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005285 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005286 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005287}
5288
5289/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005290 * xmlRelaxNGParseElement:
5291 * @ctxt: a Relax-NG parser context
5292 * @node: the element node
5293 *
5294 * parse the content of a RelaxNG element node.
5295 *
5296 * Returns the definition pointer or NULL in case of error.
5297 */
5298static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005299xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5300{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005301 xmlRelaxNGDefinePtr ret, cur, last;
5302 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005303 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005304
Daniel Veillardfd573f12003-03-16 17:52:32 +00005305 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005306 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005307 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005308 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005309 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005310 child = node->children;
5311 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005312 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5313 "xmlRelaxNGParseElement: element has no children\n",
5314 NULL, NULL);
5315 return (ret);
5316 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005317 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5318 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005319 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005320
Daniel Veillard6eadf632003-01-23 18:29:16 +00005321 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005322 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5323 "xmlRelaxNGParseElement: element has no content\n",
5324 NULL, NULL);
5325 return (ret);
5326 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005327 olddefine = ctxt->define;
5328 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005329 last = NULL;
5330 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005331 cur = xmlRelaxNGParsePattern(ctxt, child);
5332 if (cur != NULL) {
5333 cur->parent = ret;
5334 switch (cur->type) {
5335 case XML_RELAXNG_EMPTY:
5336 case XML_RELAXNG_NOT_ALLOWED:
5337 case XML_RELAXNG_TEXT:
5338 case XML_RELAXNG_ELEMENT:
5339 case XML_RELAXNG_DATATYPE:
5340 case XML_RELAXNG_VALUE:
5341 case XML_RELAXNG_LIST:
5342 case XML_RELAXNG_REF:
5343 case XML_RELAXNG_PARENTREF:
5344 case XML_RELAXNG_EXTERNALREF:
5345 case XML_RELAXNG_DEF:
5346 case XML_RELAXNG_ZEROORMORE:
5347 case XML_RELAXNG_ONEORMORE:
5348 case XML_RELAXNG_OPTIONAL:
5349 case XML_RELAXNG_CHOICE:
5350 case XML_RELAXNG_GROUP:
5351 case XML_RELAXNG_INTERLEAVE:
5352 if (last == NULL) {
5353 ret->content = last = cur;
5354 } else {
5355 if ((last->type == XML_RELAXNG_ELEMENT) &&
5356 (ret->content == last)) {
5357 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5358 if (ret->content != NULL) {
5359 ret->content->type = XML_RELAXNG_GROUP;
5360 ret->content->content = last;
5361 } else {
5362 ret->content = last;
5363 }
5364 }
5365 last->next = cur;
5366 last = cur;
5367 }
5368 break;
5369 case XML_RELAXNG_ATTRIBUTE:
5370 cur->next = ret->attrs;
5371 ret->attrs = cur;
5372 break;
5373 case XML_RELAXNG_START:
5374 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5375 "RNG Internal error, start found in element\n",
5376 NULL, NULL);
5377 break;
5378 case XML_RELAXNG_PARAM:
5379 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5380 "RNG Internal error, param found in element\n",
5381 NULL, NULL);
5382 break;
5383 case XML_RELAXNG_EXCEPT:
5384 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5385 "RNG Internal error, except found in element\n",
5386 NULL, NULL);
5387 break;
5388 case XML_RELAXNG_NOOP:
5389 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5390 "RNG Internal error, noop found in element\n",
5391 NULL, NULL);
5392 break;
5393 }
5394 }
5395 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005396 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005397 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005398 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005399}
5400
5401/**
5402 * xmlRelaxNGParsePatterns:
5403 * @ctxt: a Relax-NG parser context
5404 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005405 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005406 *
5407 * parse the content of a RelaxNG start node.
5408 *
5409 * Returns the definition pointer or NULL in case of error.
5410 */
5411static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005412xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005413 int group)
5414{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005415 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005416
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005417 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005418 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005419 if (IS_RELAXNG(nodes, "element")) {
5420 cur = xmlRelaxNGParseElement(ctxt, nodes);
5421 if (def == NULL) {
5422 def = last = cur;
5423 } else {
5424 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5425 (def == last)) {
5426 def = xmlRelaxNGNewDefine(ctxt, nodes);
5427 def->type = XML_RELAXNG_GROUP;
5428 def->content = last;
5429 }
5430 last->next = cur;
5431 last = cur;
5432 }
5433 cur->parent = parent;
5434 } else {
5435 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5436 if (cur != NULL) {
5437 if (def == NULL) {
5438 def = last = cur;
5439 } else {
5440 last->next = cur;
5441 last = cur;
5442 }
5443 }
5444 }
5445 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005446 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005447 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005448}
5449
5450/**
5451 * xmlRelaxNGParseStart:
5452 * @ctxt: a Relax-NG parser context
5453 * @nodes: start children nodes
5454 *
5455 * parse the content of a RelaxNG start node.
5456 *
5457 * Returns 0 in case of success, -1 in case of error
5458 */
5459static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005460xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5461{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005462 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005463 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005464
Daniel Veillardd2298792003-02-14 16:54:11 +00005465 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005466 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5467 NULL, NULL);
5468 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005469 }
5470 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005471 def = xmlRelaxNGNewDefine(ctxt, nodes);
5472 if (def == NULL)
5473 return (-1);
5474 def->type = XML_RELAXNG_EMPTY;
5475 if (nodes->children != NULL) {
5476 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5477 "element empty is not empty\n", NULL, NULL);
5478 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005479 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005480 def = xmlRelaxNGNewDefine(ctxt, nodes);
5481 if (def == NULL)
5482 return (-1);
5483 def->type = XML_RELAXNG_NOT_ALLOWED;
5484 if (nodes->children != NULL) {
5485 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5486 "element notAllowed is not empty\n", NULL, NULL);
5487 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005488 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005489 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005490 }
5491 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005492 last = ctxt->grammar->start;
5493 while (last->next != NULL)
5494 last = last->next;
5495 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005496 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005497 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005498 }
5499 nodes = nodes->next;
5500 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005501 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5502 "start more than one children\n", NULL, NULL);
5503 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005504 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005505 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506}
5507
5508/**
5509 * xmlRelaxNGParseGrammarContent:
5510 * @ctxt: a Relax-NG parser context
5511 * @nodes: grammar children nodes
5512 *
5513 * parse the content of a RelaxNG grammar node.
5514 *
5515 * Returns 0 in case of success, -1 in case of error
5516 */
5517static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005518xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5519 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005520{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005521 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005522
5523 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005524 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5525 "grammar has no children\n", NULL, NULL);
5526 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005527 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005528 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005529 if (IS_RELAXNG(nodes, "start")) {
5530 if (nodes->children == NULL) {
5531 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5532 "start has no children\n", NULL, NULL);
5533 } else {
5534 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5535 if (tmp != 0)
5536 ret = -1;
5537 }
5538 } else if (IS_RELAXNG(nodes, "define")) {
5539 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5540 if (tmp != 0)
5541 ret = -1;
5542 } else if (IS_RELAXNG(nodes, "include")) {
5543 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5544 if (tmp != 0)
5545 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005546 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005547 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5548 "grammar has unexpected child %s\n", nodes->name,
5549 NULL);
5550 ret = -1;
5551 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005552 nodes = nodes->next;
5553 }
5554 return (ret);
5555}
5556
5557/**
5558 * xmlRelaxNGCheckReference:
5559 * @ref: the ref
5560 * @ctxt: a Relax-NG parser context
5561 * @name: the name associated to the defines
5562 *
5563 * Applies the 4.17. combine attribute rule for all the define
5564 * element of a given grammar using the same name.
5565 */
5566static void
5567xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005568 xmlRelaxNGParserCtxtPtr ctxt,
5569 const xmlChar * name)
5570{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005571 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005572 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005573
5574 grammar = ctxt->grammar;
5575 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005576 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5577 "Internal error: no grammar in CheckReference %s\n",
5578 name, NULL);
5579 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005580 }
5581 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005582 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5583 "Internal error: reference has content in CheckReference %s\n",
5584 name, NULL);
5585 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005586 }
5587 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005588 def = xmlHashLookup(grammar->defs, name);
5589 if (def != NULL) {
5590 cur = ref;
5591 while (cur != NULL) {
5592 cur->content = def;
5593 cur = cur->nextHash;
5594 }
5595 } else {
5596 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5597 "Reference %s has no matching definition\n", name,
5598 NULL);
5599 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005600 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005601 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5602 "Reference %s has no matching definition\n", name,
5603 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005604 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005605}
5606
5607/**
5608 * xmlRelaxNGCheckCombine:
5609 * @define: the define(s) list
5610 * @ctxt: a Relax-NG parser context
5611 * @name: the name associated to the defines
5612 *
5613 * Applies the 4.17. combine attribute rule for all the define
5614 * element of a given grammar using the same name.
5615 */
5616static void
5617xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005618 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5619{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005620 xmlChar *combine;
5621 int choiceOrInterleave = -1;
5622 int missing = 0;
5623 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5624
5625 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005626 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005627 cur = define;
5628 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005629 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5630 if (combine != NULL) {
5631 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5632 if (choiceOrInterleave == -1)
5633 choiceOrInterleave = 1;
5634 else if (choiceOrInterleave == 0) {
5635 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5636 "Defines for %s use both 'choice' and 'interleave'\n",
5637 name, NULL);
5638 }
5639 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5640 if (choiceOrInterleave == -1)
5641 choiceOrInterleave = 0;
5642 else if (choiceOrInterleave == 1) {
5643 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5644 "Defines for %s use both 'choice' and 'interleave'\n",
5645 name, NULL);
5646 }
5647 } else {
5648 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5649 "Defines for %s use unknown combine value '%s''\n",
5650 name, combine);
5651 }
5652 xmlFree(combine);
5653 } else {
5654 if (missing == 0)
5655 missing = 1;
5656 else {
5657 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5658 "Some defines for %s needs the combine attribute\n",
5659 name, NULL);
5660 }
5661 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005662
Daniel Veillard4c004142003-10-07 11:33:24 +00005663 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005664 }
5665#ifdef DEBUG
5666 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005667 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5668 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005669#endif
5670 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005671 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005672 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005673 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005674 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005675 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005676 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005677 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005678 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005679 tmp = define;
5680 last = NULL;
5681 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005682 if (tmp->content != NULL) {
5683 if (tmp->content->next != NULL) {
5684 /*
5685 * we need first to create a wrapper.
5686 */
5687 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5688 if (tmp2 == NULL)
5689 break;
5690 tmp2->type = XML_RELAXNG_GROUP;
5691 tmp2->content = tmp->content;
5692 } else {
5693 tmp2 = tmp->content;
5694 }
5695 if (last == NULL) {
5696 cur->content = tmp2;
5697 } else {
5698 last->next = tmp2;
5699 }
5700 last = tmp2;
5701 }
5702 tmp->content = cur;
5703 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005704 }
5705 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005706 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005707 if (ctxt->interleaves == NULL)
5708 ctxt->interleaves = xmlHashCreate(10);
5709 if (ctxt->interleaves == NULL) {
5710 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5711 "Failed to create interleaves hash table\n", NULL,
5712 NULL);
5713 } else {
5714 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005715
Daniel Veillard4c004142003-10-07 11:33:24 +00005716 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5717 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5718 0) {
5719 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5720 "Failed to add %s to hash table\n",
5721 (const xmlChar *) tmpname, NULL);
5722 }
5723 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005724 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005725}
5726
5727/**
5728 * xmlRelaxNGCombineStart:
5729 * @ctxt: a Relax-NG parser context
5730 * @grammar: the grammar
5731 *
5732 * Applies the 4.17. combine rule for all the start
5733 * element of a given grammar.
5734 */
5735static void
5736xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005737 xmlRelaxNGGrammarPtr grammar)
5738{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005739 xmlRelaxNGDefinePtr starts;
5740 xmlChar *combine;
5741 int choiceOrInterleave = -1;
5742 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005743 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005744
Daniel Veillard2df2de22003-02-17 23:34:33 +00005745 starts = grammar->start;
5746 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005747 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005748 cur = starts;
5749 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005750 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5751 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5752 combine = NULL;
5753 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5754 "Internal error: start element not found\n", NULL,
5755 NULL);
5756 } else {
5757 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5758 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005759
Daniel Veillard4c004142003-10-07 11:33:24 +00005760 if (combine != NULL) {
5761 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5762 if (choiceOrInterleave == -1)
5763 choiceOrInterleave = 1;
5764 else if (choiceOrInterleave == 0) {
5765 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5766 "<start> use both 'choice' and 'interleave'\n",
5767 NULL, NULL);
5768 }
5769 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5770 if (choiceOrInterleave == -1)
5771 choiceOrInterleave = 0;
5772 else if (choiceOrInterleave == 1) {
5773 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5774 "<start> use both 'choice' and 'interleave'\n",
5775 NULL, NULL);
5776 }
5777 } else {
5778 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5779 "<start> uses unknown combine value '%s''\n",
5780 combine, NULL);
5781 }
5782 xmlFree(combine);
5783 } else {
5784 if (missing == 0)
5785 missing = 1;
5786 else {
5787 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5788 "Some <start> element miss the combine attribute\n",
5789 NULL, NULL);
5790 }
5791 }
5792
5793 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005794 }
5795#ifdef DEBUG
5796 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005797 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5798 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005799#endif
5800 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005801 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005802 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005803 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005804 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005805 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005806 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005807 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005808 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005809 cur->content = grammar->start;
5810 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005811 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005812 if (ctxt->interleaves == NULL)
5813 ctxt->interleaves = xmlHashCreate(10);
5814 if (ctxt->interleaves == NULL) {
5815 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5816 "Failed to create interleaves hash table\n", NULL,
5817 NULL);
5818 } else {
5819 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005820
Daniel Veillard4c004142003-10-07 11:33:24 +00005821 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5822 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5823 0) {
5824 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5825 "Failed to add %s to hash table\n",
5826 (const xmlChar *) tmpname, NULL);
5827 }
5828 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005829 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005830}
5831
5832/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005833 * xmlRelaxNGCheckCycles:
5834 * @ctxt: a Relax-NG parser context
5835 * @nodes: grammar children nodes
5836 * @depth: the counter
5837 *
5838 * Check for cycles.
5839 *
5840 * Returns 0 if check passed, and -1 in case of error
5841 */
5842static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005843xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5844 xmlRelaxNGDefinePtr cur, int depth)
5845{
Daniel Veillardd4310742003-02-18 21:12:46 +00005846 int ret = 0;
5847
5848 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005849 if ((cur->type == XML_RELAXNG_REF) ||
5850 (cur->type == XML_RELAXNG_PARENTREF)) {
5851 if (cur->depth == -1) {
5852 cur->depth = depth;
5853 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5854 cur->depth = -2;
5855 } else if (depth == cur->depth) {
5856 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5857 "Detected a cycle in %s references\n",
5858 cur->name, NULL);
5859 return (-1);
5860 }
5861 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5862 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5863 } else {
5864 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5865 }
5866 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005867 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005868 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005869}
5870
5871/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005872 * xmlRelaxNGTryUnlink:
5873 * @ctxt: a Relax-NG parser context
5874 * @cur: the definition to unlink
5875 * @parent: the parent definition
5876 * @prev: the previous sibling definition
5877 *
5878 * Try to unlink a definition. If not possble make it a NOOP
5879 *
5880 * Returns the new prev definition
5881 */
5882static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005883xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5884 xmlRelaxNGDefinePtr cur,
5885 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5886{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005887 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005888 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005889 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005890 if (parent != NULL) {
5891 if (parent->content == cur)
5892 parent->content = cur->next;
5893 else if (parent->attrs == cur)
5894 parent->attrs = cur->next;
5895 else if (parent->nameClass == cur)
5896 parent->nameClass = cur->next;
5897 } else {
5898 cur->type = XML_RELAXNG_NOOP;
5899 prev = cur;
5900 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005901 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005902 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005903}
5904
5905/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005906 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005907 * @ctxt: a Relax-NG parser context
5908 * @nodes: grammar children nodes
5909 *
5910 * Check for simplification of empty and notAllowed
5911 */
5912static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005913xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5914 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5915{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005916 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005917
Daniel Veillardfd573f12003-03-16 17:52:32 +00005918 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005919 if ((cur->type == XML_RELAXNG_REF) ||
5920 (cur->type == XML_RELAXNG_PARENTREF)) {
5921 if (cur->depth != -3) {
5922 cur->depth = -3;
5923 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5924 }
5925 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5926 cur->parent = parent;
5927 if ((parent != NULL) &&
5928 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5929 (parent->type == XML_RELAXNG_LIST) ||
5930 (parent->type == XML_RELAXNG_GROUP) ||
5931 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5932 (parent->type == XML_RELAXNG_ONEORMORE) ||
5933 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5934 parent->type = XML_RELAXNG_NOT_ALLOWED;
5935 break;
5936 }
5937 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5938 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5939 } else
5940 prev = cur;
5941 } else if (cur->type == XML_RELAXNG_EMPTY) {
5942 cur->parent = parent;
5943 if ((parent != NULL) &&
5944 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5945 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5946 parent->type = XML_RELAXNG_EMPTY;
5947 break;
5948 }
5949 if ((parent != NULL) &&
5950 ((parent->type == XML_RELAXNG_GROUP) ||
5951 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5952 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5953 } else
5954 prev = cur;
5955 } else {
5956 cur->parent = parent;
5957 if (cur->content != NULL)
5958 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5959 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5960 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5961 if (cur->nameClass != NULL)
5962 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5963 /*
5964 * On Elements, try to move attribute only generating rules on
5965 * the attrs rules.
5966 */
5967 if (cur->type == XML_RELAXNG_ELEMENT) {
5968 int attronly;
5969 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005970
Daniel Veillard4c004142003-10-07 11:33:24 +00005971 while (cur->content != NULL) {
5972 attronly =
5973 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5974 if (attronly == 1) {
5975 /*
5976 * migrate cur->content to attrs
5977 */
5978 tmp = cur->content;
5979 cur->content = tmp->next;
5980 tmp->next = cur->attrs;
5981 cur->attrs = tmp;
5982 } else {
5983 /*
5984 * cur->content can generate elements or text
5985 */
5986 break;
5987 }
5988 }
5989 pre = cur->content;
5990 while ((pre != NULL) && (pre->next != NULL)) {
5991 tmp = pre->next;
5992 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5993 if (attronly == 1) {
5994 /*
5995 * migrate tmp to attrs
5996 */
5997 pre->next = tmp->next;
5998 tmp->next = cur->attrs;
5999 cur->attrs = tmp;
6000 } else {
6001 pre = tmp;
6002 }
6003 }
6004 }
6005 /*
6006 * This may result in a simplification
6007 */
6008 if ((cur->type == XML_RELAXNG_GROUP) ||
6009 (cur->type == XML_RELAXNG_INTERLEAVE)) {
6010 if (cur->content == NULL)
6011 cur->type = XML_RELAXNG_EMPTY;
6012 else if (cur->content->next == NULL) {
6013 if ((parent == NULL) && (prev == NULL)) {
6014 cur->type = XML_RELAXNG_NOOP;
6015 } else if (prev == NULL) {
6016 parent->content = cur->content;
6017 cur->content->next = cur->next;
6018 cur = cur->content;
6019 } else {
6020 cur->content->next = cur->next;
6021 prev->next = cur->content;
6022 cur = cur->content;
6023 }
6024 }
6025 }
6026 /*
6027 * the current node may have been transformed back
6028 */
6029 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6030 (cur->content != NULL) &&
6031 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6032 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6033 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6034 if ((parent != NULL) &&
6035 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6036 (parent->type == XML_RELAXNG_LIST) ||
6037 (parent->type == XML_RELAXNG_GROUP) ||
6038 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6039 (parent->type == XML_RELAXNG_ONEORMORE) ||
6040 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6041 parent->type = XML_RELAXNG_NOT_ALLOWED;
6042 break;
6043 }
6044 if ((parent != NULL) &&
6045 (parent->type == XML_RELAXNG_CHOICE)) {
6046 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6047 } else
6048 prev = cur;
6049 } else if (cur->type == XML_RELAXNG_EMPTY) {
6050 if ((parent != NULL) &&
6051 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6052 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6053 parent->type = XML_RELAXNG_EMPTY;
6054 break;
6055 }
6056 if ((parent != NULL) &&
6057 ((parent->type == XML_RELAXNG_GROUP) ||
6058 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6059 (parent->type == XML_RELAXNG_CHOICE))) {
6060 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6061 } else
6062 prev = cur;
6063 } else {
6064 prev = cur;
6065 }
6066 }
6067 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006068 }
6069}
6070
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006071/**
6072 * xmlRelaxNGGroupContentType:
6073 * @ct1: the first content type
6074 * @ct2: the second content type
6075 *
6076 * Try to group 2 content types
6077 *
6078 * Returns the content type
6079 */
6080static xmlRelaxNGContentType
6081xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006082 xmlRelaxNGContentType ct2)
6083{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006084 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006085 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6086 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006087 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006088 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006089 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006090 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006091 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006092 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6093 return (XML_RELAXNG_CONTENT_COMPLEX);
6094 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006095}
6096
6097/**
6098 * xmlRelaxNGMaxContentType:
6099 * @ct1: the first content type
6100 * @ct2: the second content type
6101 *
6102 * Compute the max content-type
6103 *
6104 * Returns the content type
6105 */
6106static xmlRelaxNGContentType
6107xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006108 xmlRelaxNGContentType ct2)
6109{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006110 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006111 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6112 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006113 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006114 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6115 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006116 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006117 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6118 return (XML_RELAXNG_CONTENT_COMPLEX);
6119 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006120}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006121
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006122/**
6123 * xmlRelaxNGCheckRules:
6124 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006125 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006126 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006127 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006128 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006129 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006130 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006131 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006132 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006133static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006134xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6135 xmlRelaxNGDefinePtr cur, int flags,
6136 xmlRelaxNGType ptype)
6137{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006138 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006139 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006140
Daniel Veillardfd573f12003-03-16 17:52:32 +00006141 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006142 ret = XML_RELAXNG_CONTENT_EMPTY;
6143 if ((cur->type == XML_RELAXNG_REF) ||
6144 (cur->type == XML_RELAXNG_PARENTREF)) {
Daniel Veillard63d68a32005-03-31 13:50:00 +00006145 /*
6146 * This should actually be caught by list//element(ref) at the
6147 * element boundaries, c.f. Bug #159968 local refs are dropped
6148 * in step 4.19.
6149 */
6150#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00006151 if (flags & XML_RELAXNG_IN_LIST) {
6152 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6153 "Found forbidden pattern list//ref\n", NULL,
6154 NULL);
6155 }
Daniel Veillard63d68a32005-03-31 13:50:00 +00006156#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00006157 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6158 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6159 "Found forbidden pattern data/except//ref\n",
6160 NULL, NULL);
6161 }
6162 if (cur->depth > -4) {
6163 cur->depth = -4;
6164 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6165 flags, cur->type);
6166 cur->depth = ret - 15;
6167 } else if (cur->depth == -4) {
6168 ret = XML_RELAXNG_CONTENT_COMPLEX;
6169 } else {
6170 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6171 }
6172 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6173 /*
6174 * The 7.3 Attribute derivation rule for groups is plugged there
6175 */
6176 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6177 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6178 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6179 "Found forbidden pattern data/except//element(ref)\n",
6180 NULL, NULL);
6181 }
6182 if (flags & XML_RELAXNG_IN_LIST) {
6183 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6184 "Found forbidden pattern list//element(ref)\n",
6185 NULL, NULL);
6186 }
6187 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6188 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6189 "Found forbidden pattern attribute//element(ref)\n",
6190 NULL, NULL);
6191 }
6192 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6193 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6194 "Found forbidden pattern attribute//element(ref)\n",
6195 NULL, NULL);
6196 }
6197 /*
6198 * reset since in the simple form elements are only child
6199 * of grammar/define
6200 */
6201 nflags = 0;
6202 ret =
6203 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6204 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6205 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6206 "Element %s attributes have a content type error\n",
6207 cur->name, NULL);
6208 }
6209 ret =
6210 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6211 cur->type);
6212 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6213 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6214 "Element %s has a content type error\n",
6215 cur->name, NULL);
6216 } else {
6217 ret = XML_RELAXNG_CONTENT_COMPLEX;
6218 }
6219 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6220 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6221 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6222 "Found forbidden pattern attribute//attribute\n",
6223 NULL, NULL);
6224 }
6225 if (flags & XML_RELAXNG_IN_LIST) {
6226 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6227 "Found forbidden pattern list//attribute\n",
6228 NULL, NULL);
6229 }
6230 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6231 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6232 "Found forbidden pattern oneOrMore//group//attribute\n",
6233 NULL, NULL);
6234 }
6235 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6236 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6237 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6238 NULL, NULL);
6239 }
6240 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6241 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6242 "Found forbidden pattern data/except//attribute\n",
6243 NULL, NULL);
6244 }
6245 if (flags & XML_RELAXNG_IN_START) {
6246 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6247 "Found forbidden pattern start//attribute\n",
6248 NULL, NULL);
6249 }
6250 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6251 && (cur->name == NULL)) {
6252 if (cur->ns == NULL) {
6253 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6254 "Found anyName attribute without oneOrMore ancestor\n",
6255 NULL, NULL);
6256 } else {
6257 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6258 "Found nsName attribute without oneOrMore ancestor\n",
6259 NULL, NULL);
6260 }
6261 }
6262 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6263 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6264 ret = XML_RELAXNG_CONTENT_EMPTY;
6265 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6266 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6267 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6268 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6269 "Found forbidden pattern data/except//oneOrMore\n",
6270 NULL, NULL);
6271 }
6272 if (flags & XML_RELAXNG_IN_START) {
6273 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6274 "Found forbidden pattern start//oneOrMore\n",
6275 NULL, NULL);
6276 }
6277 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6278 ret =
6279 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6280 cur->type);
6281 ret = xmlRelaxNGGroupContentType(ret, ret);
6282 } else if (cur->type == XML_RELAXNG_LIST) {
6283 if (flags & XML_RELAXNG_IN_LIST) {
6284 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6285 "Found forbidden pattern list//list\n", NULL,
6286 NULL);
6287 }
6288 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6289 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6290 "Found forbidden pattern data/except//list\n",
6291 NULL, NULL);
6292 }
6293 if (flags & XML_RELAXNG_IN_START) {
6294 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6295 "Found forbidden pattern start//list\n", NULL,
6296 NULL);
6297 }
6298 nflags = flags | XML_RELAXNG_IN_LIST;
6299 ret =
6300 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6301 cur->type);
6302 } else if (cur->type == XML_RELAXNG_GROUP) {
6303 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6304 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6305 "Found forbidden pattern data/except//group\n",
6306 NULL, NULL);
6307 }
6308 if (flags & XML_RELAXNG_IN_START) {
6309 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6310 "Found forbidden pattern start//group\n", NULL,
6311 NULL);
6312 }
6313 if (flags & XML_RELAXNG_IN_ONEORMORE)
6314 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6315 else
6316 nflags = flags;
6317 ret =
6318 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6319 cur->type);
6320 /*
6321 * The 7.3 Attribute derivation rule for groups is plugged there
6322 */
6323 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6324 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6325 if (flags & XML_RELAXNG_IN_LIST) {
6326 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6327 "Found forbidden pattern list//interleave\n",
6328 NULL, NULL);
6329 }
6330 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6331 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6332 "Found forbidden pattern data/except//interleave\n",
6333 NULL, NULL);
6334 }
6335 if (flags & XML_RELAXNG_IN_START) {
6336 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6337 "Found forbidden pattern start//interleave\n",
6338 NULL, NULL);
6339 }
6340 if (flags & XML_RELAXNG_IN_ONEORMORE)
6341 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6342 else
6343 nflags = flags;
6344 ret =
6345 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6346 cur->type);
6347 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6348 if ((cur->parent != NULL) &&
6349 (cur->parent->type == XML_RELAXNG_DATATYPE))
6350 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6351 else
6352 nflags = flags;
6353 ret =
6354 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6355 cur->type);
6356 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6357 if (flags & XML_RELAXNG_IN_START) {
6358 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6359 "Found forbidden pattern start//data\n", NULL,
6360 NULL);
6361 }
6362 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6363 ret = XML_RELAXNG_CONTENT_SIMPLE;
6364 } else if (cur->type == XML_RELAXNG_VALUE) {
6365 if (flags & XML_RELAXNG_IN_START) {
6366 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6367 "Found forbidden pattern start//value\n", NULL,
6368 NULL);
6369 }
6370 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6371 ret = XML_RELAXNG_CONTENT_SIMPLE;
6372 } else if (cur->type == XML_RELAXNG_TEXT) {
6373 if (flags & XML_RELAXNG_IN_LIST) {
6374 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6375 "Found forbidden pattern list//text\n", NULL,
6376 NULL);
6377 }
6378 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6379 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6380 "Found forbidden pattern data/except//text\n",
6381 NULL, NULL);
6382 }
6383 if (flags & XML_RELAXNG_IN_START) {
6384 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6385 "Found forbidden pattern start//text\n", NULL,
6386 NULL);
6387 }
6388 ret = XML_RELAXNG_CONTENT_COMPLEX;
6389 } else if (cur->type == XML_RELAXNG_EMPTY) {
6390 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6391 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6392 "Found forbidden pattern data/except//empty\n",
6393 NULL, NULL);
6394 }
6395 if (flags & XML_RELAXNG_IN_START) {
6396 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6397 "Found forbidden pattern start//empty\n", NULL,
6398 NULL);
6399 }
6400 ret = XML_RELAXNG_CONTENT_EMPTY;
6401 } else if (cur->type == XML_RELAXNG_CHOICE) {
6402 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6403 ret =
6404 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6405 } else {
6406 ret =
6407 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6408 }
6409 cur = cur->next;
6410 if (ptype == XML_RELAXNG_GROUP) {
6411 val = xmlRelaxNGGroupContentType(val, ret);
6412 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6413 tmp = xmlRelaxNGGroupContentType(val, ret);
6414 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6415 tmp = xmlRelaxNGMaxContentType(val, ret);
6416 } else if (ptype == XML_RELAXNG_CHOICE) {
6417 val = xmlRelaxNGMaxContentType(val, ret);
6418 } else if (ptype == XML_RELAXNG_LIST) {
6419 val = XML_RELAXNG_CONTENT_SIMPLE;
6420 } else if (ptype == XML_RELAXNG_EXCEPT) {
6421 if (ret == XML_RELAXNG_CONTENT_ERROR)
6422 val = XML_RELAXNG_CONTENT_ERROR;
6423 else
6424 val = XML_RELAXNG_CONTENT_SIMPLE;
6425 } else {
6426 val = xmlRelaxNGGroupContentType(val, ret);
6427 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006428
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006429 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006430 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006431}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006432
6433/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006434 * xmlRelaxNGParseGrammar:
6435 * @ctxt: a Relax-NG parser context
6436 * @nodes: grammar children nodes
6437 *
6438 * parse a Relax-NG <grammar> node
6439 *
6440 * Returns the internal xmlRelaxNGGrammarPtr built or
6441 * NULL in case of error
6442 */
6443static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006444xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6445{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006446 xmlRelaxNGGrammarPtr ret, tmp, old;
6447
Daniel Veillardc482e262003-02-26 14:48:48 +00006448#ifdef DEBUG_GRAMMAR
6449 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6450#endif
6451
Daniel Veillard6eadf632003-01-23 18:29:16 +00006452 ret = xmlRelaxNGNewGrammar(ctxt);
6453 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006454 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006455
6456 /*
6457 * Link the new grammar in the tree
6458 */
6459 ret->parent = ctxt->grammar;
6460 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006461 tmp = ctxt->grammar->children;
6462 if (tmp == NULL) {
6463 ctxt->grammar->children = ret;
6464 } else {
6465 while (tmp->next != NULL)
6466 tmp = tmp->next;
6467 tmp->next = ret;
6468 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469 }
6470
6471 old = ctxt->grammar;
6472 ctxt->grammar = ret;
6473 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6474 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006475 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006476 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6477 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006478 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006479 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6480 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006481 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006482
6483 /*
6484 * Apply 4.17 mergingd rules to defines and starts
6485 */
6486 xmlRelaxNGCombineStart(ctxt, ret);
6487 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006488 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6489 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006490 }
6491
6492 /*
6493 * link together defines and refs in this grammar
6494 */
6495 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006496 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6497 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006498 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006499
Daniel Veillard6eadf632003-01-23 18:29:16 +00006500 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006501 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006502}
6503
6504/**
6505 * xmlRelaxNGParseDocument:
6506 * @ctxt: a Relax-NG parser context
6507 * @node: the root node of the RelaxNG schema
6508 *
6509 * parse a Relax-NG definition resource and build an internal
6510 * xmlRelaxNG struture which can be used to validate instances.
6511 *
6512 * Returns the internal XML RelaxNG structure built or
6513 * NULL in case of error
6514 */
6515static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006516xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6517{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006518 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006519 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006520 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006521
6522 if ((ctxt == NULL) || (node == NULL))
6523 return (NULL);
6524
6525 schema = xmlRelaxNGNewRelaxNG(ctxt);
6526 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006527 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006528
Daniel Veillard276be4a2003-01-24 01:03:34 +00006529 olddefine = ctxt->define;
6530 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006531 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006532 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006533 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006534 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006535
Daniel Veillard4c004142003-10-07 11:33:24 +00006536 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6537 if (schema->topgrammar == NULL) {
6538 return (schema);
6539 }
6540 /*
6541 * Link the new grammar in the tree
6542 */
6543 ret->parent = ctxt->grammar;
6544 if (ctxt->grammar != NULL) {
6545 tmp = ctxt->grammar->children;
6546 if (tmp == NULL) {
6547 ctxt->grammar->children = ret;
6548 } else {
6549 while (tmp->next != NULL)
6550 tmp = tmp->next;
6551 tmp->next = ret;
6552 }
6553 }
6554 old = ctxt->grammar;
6555 ctxt->grammar = ret;
6556 xmlRelaxNGParseStart(ctxt, node);
6557 if (old != NULL)
6558 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006559 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006560 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006561 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006562 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6563 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6564 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6565 while ((schema->topgrammar->start != NULL) &&
6566 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6567 (schema->topgrammar->start->next != NULL))
6568 schema->topgrammar->start =
6569 schema->topgrammar->start->content;
6570 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6571 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6572 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006573 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006574#ifdef DEBUG
6575 if (schema == NULL)
6576 xmlGenericError(xmlGenericErrorContext,
6577 "xmlRelaxNGParseDocument() failed\n");
6578#endif
6579
6580 return (schema);
6581}
6582
6583/************************************************************************
6584 * *
6585 * Reading RelaxNGs *
6586 * *
6587 ************************************************************************/
6588
6589/**
6590 * xmlRelaxNGNewParserCtxt:
6591 * @URL: the location of the schema
6592 *
6593 * Create an XML RelaxNGs parse context for that file/resource expected
6594 * to contain an XML RelaxNGs file.
6595 *
6596 * Returns the parser context or NULL in case of error
6597 */
6598xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006599xmlRelaxNGNewParserCtxt(const char *URL)
6600{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006601 xmlRelaxNGParserCtxtPtr ret;
6602
6603 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006604 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006605
Daniel Veillard4c004142003-10-07 11:33:24 +00006606 ret =
6607 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006608 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006609 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006610 return (NULL);
6611 }
6612 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006613 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006614 ret->error = xmlGenericError;
6615 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006616 return (ret);
6617}
6618
6619/**
6620 * xmlRelaxNGNewMemParserCtxt:
6621 * @buffer: a pointer to a char array containing the schemas
6622 * @size: the size of the array
6623 *
6624 * Create an XML RelaxNGs parse context for that memory buffer expected
6625 * to contain an XML RelaxNGs file.
6626 *
6627 * Returns the parser context or NULL in case of error
6628 */
6629xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006630xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6631{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006632 xmlRelaxNGParserCtxtPtr ret;
6633
6634 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006635 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006636
Daniel Veillard4c004142003-10-07 11:33:24 +00006637 ret =
6638 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006639 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006640 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006641 return (NULL);
6642 }
6643 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6644 ret->buffer = buffer;
6645 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006646 ret->error = xmlGenericError;
6647 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006648 return (ret);
6649}
6650
6651/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006652 * xmlRelaxNGNewDocParserCtxt:
6653 * @doc: a preparsed document tree
6654 *
6655 * Create an XML RelaxNGs parser context for that document.
6656 * Note: since the process of compiling a RelaxNG schemas modifies the
6657 * document, the @doc parameter is duplicated internally.
6658 *
6659 * Returns the parser context or NULL in case of error
6660 */
6661xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006662xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6663{
Daniel Veillard33300b42003-04-17 09:09:19 +00006664 xmlRelaxNGParserCtxtPtr ret;
6665 xmlDocPtr copy;
6666
6667 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006668 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006669 copy = xmlCopyDoc(doc, 1);
6670 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006671 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006672
Daniel Veillard4c004142003-10-07 11:33:24 +00006673 ret =
6674 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006675 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006676 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006677 return (NULL);
6678 }
6679 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6680 ret->document = copy;
Daniel Veillard42595322004-11-08 10:52:06 +00006681 ret->freedoc = 1;
Daniel Veillard33300b42003-04-17 09:09:19 +00006682 ret->userData = xmlGenericErrorContext;
6683 return (ret);
6684}
6685
6686/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006687 * xmlRelaxNGFreeParserCtxt:
6688 * @ctxt: the schema parser context
6689 *
6690 * Free the resources associated to the schema parser context
6691 */
6692void
Daniel Veillard4c004142003-10-07 11:33:24 +00006693xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6694{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006695 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006696 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006697 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006698 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006699 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006700 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006701 if (ctxt->interleaves != NULL)
6702 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006703 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006704 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006705 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006706 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006707 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006708 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006709 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006710 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006711 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006712 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006713
Daniel Veillard4c004142003-10-07 11:33:24 +00006714 for (i = 0; i < ctxt->defNr; i++)
6715 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6716 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006717 }
Daniel Veillard42595322004-11-08 10:52:06 +00006718 if ((ctxt->document != NULL) && (ctxt->freedoc))
6719 xmlFreeDoc(ctxt->document);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006720 xmlFree(ctxt);
6721}
6722
Daniel Veillard6eadf632003-01-23 18:29:16 +00006723/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006724 * xmlRelaxNGNormExtSpace:
6725 * @value: a value
6726 *
6727 * Removes the leading and ending spaces of the value
6728 * The string is modified "in situ"
6729 */
6730static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006731xmlRelaxNGNormExtSpace(xmlChar * value)
6732{
Daniel Veillardd2298792003-02-14 16:54:11 +00006733 xmlChar *start = value;
6734 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006735
Daniel Veillard4c004142003-10-07 11:33:24 +00006736 if (value == NULL)
6737 return;
6738
William M. Brack76e95df2003-10-18 16:20:14 +00006739 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006740 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006741 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006742 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006743 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006744 cur++;
6745 if (*cur == 0)
6746 return;
6747 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006748 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006749 cur++;
6750 if (*cur == 0) {
6751 *start = 0;
6752 return;
6753 }
6754 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006755 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006756 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006757 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006758 *start++ = *cur++;
6759 if (*cur == 0) {
6760 *start = 0;
6761 return;
6762 }
6763 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006764 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006765 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006766 if (*cur == 0) {
6767 *start = 0;
6768 return;
6769 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006770 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006771 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006772 }
6773}
6774
6775/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006776 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006777 * @ctxt: a Relax-NG parser context
6778 * @node: a Relax-NG node
6779 *
6780 * Check all the attributes on the given node
6781 */
6782static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006783xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6784{
Daniel Veillardd2298792003-02-14 16:54:11 +00006785 xmlAttrPtr cur, next;
6786
6787 cur = node->properties;
6788 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006789 next = cur->next;
6790 if ((cur->ns == NULL) ||
6791 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6792 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6793 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6794 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6795 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6796 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6797 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6798 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6799 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6800 "Attribute %s is not allowed on %s\n",
6801 cur->name, node->name);
6802 }
6803 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6804 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6805 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6806 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6807 "Attribute %s is not allowed on %s\n",
6808 cur->name, node->name);
6809 }
6810 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6811 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6812 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6813 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6814 "Attribute %s is not allowed on %s\n",
6815 cur->name, node->name);
6816 }
6817 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6818 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6819 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6820 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6821 "Attribute %s is not allowed on %s\n",
6822 cur->name, node->name);
6823 }
6824 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6825 xmlChar *val;
6826 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006827
Daniel Veillard4c004142003-10-07 11:33:24 +00006828 val = xmlNodeListGetString(node->doc, cur->children, 1);
6829 if (val != NULL) {
6830 if (val[0] != 0) {
6831 uri = xmlParseURI((const char *) val);
6832 if (uri == NULL) {
6833 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6834 "Attribute %s contains invalid URI %s\n",
6835 cur->name, val);
6836 } else {
6837 if (uri->scheme == NULL) {
6838 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6839 "Attribute %s URI %s is not absolute\n",
6840 cur->name, val);
6841 }
6842 if (uri->fragment != NULL) {
6843 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6844 "Attribute %s URI %s has a fragment ID\n",
6845 cur->name, val);
6846 }
6847 xmlFreeURI(uri);
6848 }
6849 }
6850 xmlFree(val);
6851 }
6852 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6853 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6854 "Unknown attribute %s on %s\n", cur->name,
6855 node->name);
6856 }
6857 }
6858 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006859 }
6860}
6861
6862/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006863 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006864 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006865 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006866 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006867 * Cleanup the subtree from unwanted nodes for parsing, resolve
6868 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006869 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006870static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006871xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6872{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006873 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006874
Daniel Veillard6eadf632003-01-23 18:29:16 +00006875 delete = NULL;
6876 cur = root;
6877 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006878 if (delete != NULL) {
6879 xmlUnlinkNode(delete);
6880 xmlFreeNode(delete);
6881 delete = NULL;
6882 }
6883 if (cur->type == XML_ELEMENT_NODE) {
6884 /*
6885 * Simplification 4.1. Annotations
6886 */
6887 if ((cur->ns == NULL) ||
6888 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6889 if ((cur->parent != NULL) &&
6890 (cur->parent->type == XML_ELEMENT_NODE) &&
6891 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6892 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6893 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6894 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6895 "element %s doesn't allow foreign elements\n",
6896 cur->parent->name, NULL);
6897 }
6898 delete = cur;
6899 goto skip_children;
6900 } else {
6901 xmlRelaxNGCleanupAttributes(ctxt, cur);
6902 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6903 xmlChar *href, *ns, *base, *URL;
6904 xmlRelaxNGDocumentPtr docu;
6905 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006906 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006907
Daniel Veillard4c004142003-10-07 11:33:24 +00006908 ns = xmlGetProp(cur, BAD_CAST "ns");
6909 if (ns == NULL) {
6910 tmp = cur->parent;
6911 while ((tmp != NULL) &&
6912 (tmp->type == XML_ELEMENT_NODE)) {
6913 ns = xmlGetProp(tmp, BAD_CAST "ns");
6914 if (ns != NULL)
6915 break;
6916 tmp = tmp->parent;
6917 }
6918 }
6919 href = xmlGetProp(cur, BAD_CAST "href");
6920 if (href == NULL) {
6921 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6922 "xmlRelaxNGParse: externalRef has no href attribute\n",
6923 NULL, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006924 if (ns != NULL)
6925 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006926 delete = cur;
6927 goto skip_children;
6928 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006929 uri = xmlParseURI((const char *) href);
6930 if (uri == NULL) {
6931 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6932 "Incorrect URI for externalRef %s\n",
6933 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006934 if (ns != NULL)
6935 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00006936 if (href != NULL)
6937 xmlFree(href);
6938 delete = cur;
6939 goto skip_children;
6940 }
6941 if (uri->fragment != NULL) {
6942 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6943 "Fragment forbidden in URI for externalRef %s\n",
6944 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006945 if (ns != NULL)
6946 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00006947 xmlFreeURI(uri);
6948 if (href != NULL)
6949 xmlFree(href);
6950 delete = cur;
6951 goto skip_children;
6952 }
6953 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006954 base = xmlNodeGetBase(cur->doc, cur);
6955 URL = xmlBuildURI(href, base);
6956 if (URL == NULL) {
6957 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6958 "Failed to compute URL for externalRef %s\n",
6959 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006960 if (ns != NULL)
6961 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006962 if (href != NULL)
6963 xmlFree(href);
6964 if (base != NULL)
6965 xmlFree(base);
6966 delete = cur;
6967 goto skip_children;
6968 }
6969 if (href != NULL)
6970 xmlFree(href);
6971 if (base != NULL)
6972 xmlFree(base);
6973 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6974 if (docu == NULL) {
6975 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6976 "Failed to load externalRef %s\n", URL,
6977 NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006978 if (ns != NULL)
6979 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006980 xmlFree(URL);
6981 delete = cur;
6982 goto skip_children;
6983 }
6984 if (ns != NULL)
6985 xmlFree(ns);
6986 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006987 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006988 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6989 xmlChar *href, *ns, *base, *URL;
6990 xmlRelaxNGIncludePtr incl;
6991 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006992
Daniel Veillard4c004142003-10-07 11:33:24 +00006993 href = xmlGetProp(cur, BAD_CAST "href");
6994 if (href == NULL) {
6995 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6996 "xmlRelaxNGParse: include has no href attribute\n",
6997 NULL, NULL);
6998 delete = cur;
6999 goto skip_children;
7000 }
7001 base = xmlNodeGetBase(cur->doc, cur);
7002 URL = xmlBuildURI(href, base);
7003 if (URL == NULL) {
7004 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7005 "Failed to compute URL for include %s\n",
7006 href, NULL);
7007 if (href != NULL)
7008 xmlFree(href);
7009 if (base != NULL)
7010 xmlFree(base);
7011 delete = cur;
7012 goto skip_children;
7013 }
7014 if (href != NULL)
7015 xmlFree(href);
7016 if (base != NULL)
7017 xmlFree(base);
7018 ns = xmlGetProp(cur, BAD_CAST "ns");
7019 if (ns == NULL) {
7020 tmp = cur->parent;
7021 while ((tmp != NULL) &&
7022 (tmp->type == XML_ELEMENT_NODE)) {
7023 ns = xmlGetProp(tmp, BAD_CAST "ns");
7024 if (ns != NULL)
7025 break;
7026 tmp = tmp->parent;
7027 }
7028 }
7029 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7030 if (ns != NULL)
7031 xmlFree(ns);
7032 if (incl == NULL) {
7033 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7034 "Failed to load include %s\n", URL,
7035 NULL);
7036 xmlFree(URL);
7037 delete = cur;
7038 goto skip_children;
7039 }
7040 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007041 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007042 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7043 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7044 {
7045 xmlChar *name, *ns;
7046 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007047
Daniel Veillard4c004142003-10-07 11:33:24 +00007048 /*
7049 * Simplification 4.8. name attribute of element
7050 * and attribute elements
7051 */
7052 name = xmlGetProp(cur, BAD_CAST "name");
7053 if (name != NULL) {
7054 if (cur->children == NULL) {
7055 text =
7056 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7057 name);
7058 } else {
7059 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007060
Daniel Veillard03a53c32004-10-26 16:06:51 +00007061 node = xmlNewDocNode(cur->doc, cur->ns,
7062 BAD_CAST "name", NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00007063 if (node != NULL) {
7064 xmlAddPrevSibling(cur->children, node);
7065 text = xmlNewText(name);
7066 xmlAddChild(node, text);
7067 text = node;
7068 }
7069 }
7070 if (text == NULL) {
7071 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7072 "Failed to create a name %s element\n",
7073 name, NULL);
7074 }
7075 xmlUnsetProp(cur, BAD_CAST "name");
7076 xmlFree(name);
7077 ns = xmlGetProp(cur, BAD_CAST "ns");
7078 if (ns != NULL) {
7079 if (text != NULL) {
7080 xmlSetProp(text, BAD_CAST "ns", ns);
7081 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7082 }
7083 xmlFree(ns);
7084 } else if (xmlStrEqual(cur->name,
7085 BAD_CAST "attribute")) {
7086 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7087 }
7088 }
7089 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7090 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7091 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7092 /*
7093 * Simplification 4.8. name attribute of element
7094 * and attribute elements
7095 */
7096 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7097 xmlNodePtr node;
7098 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007099
Daniel Veillard4c004142003-10-07 11:33:24 +00007100 node = cur->parent;
7101 while ((node != NULL) &&
7102 (node->type == XML_ELEMENT_NODE)) {
7103 ns = xmlGetProp(node, BAD_CAST "ns");
7104 if (ns != NULL) {
7105 break;
7106 }
7107 node = node->parent;
7108 }
7109 if (ns == NULL) {
7110 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7111 } else {
7112 xmlSetProp(cur, BAD_CAST "ns", ns);
7113 xmlFree(ns);
7114 }
7115 }
7116 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7117 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007118
Daniel Veillard4c004142003-10-07 11:33:24 +00007119 /*
7120 * Simplification: 4.10. QNames
7121 */
7122 name = xmlNodeGetContent(cur);
7123 if (name != NULL) {
7124 local = xmlSplitQName2(name, &prefix);
7125 if (local != NULL) {
7126 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007127
Daniel Veillard4c004142003-10-07 11:33:24 +00007128 ns = xmlSearchNs(cur->doc, cur, prefix);
7129 if (ns == NULL) {
7130 xmlRngPErr(ctxt, cur,
7131 XML_RNGP_PREFIX_UNDEFINED,
7132 "xmlRelaxNGParse: no namespace for prefix %s\n",
7133 prefix, NULL);
7134 } else {
7135 xmlSetProp(cur, BAD_CAST "ns",
7136 ns->href);
7137 xmlNodeSetContent(cur, local);
7138 }
7139 xmlFree(local);
7140 xmlFree(prefix);
7141 }
7142 xmlFree(name);
7143 }
7144 }
7145 /*
7146 * 4.16
7147 */
7148 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7149 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7150 xmlRngPErr(ctxt, cur,
7151 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7152 "Found nsName/except//nsName forbidden construct\n",
7153 NULL, NULL);
7154 }
7155 }
7156 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7157 (cur != root)) {
7158 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007159
Daniel Veillard4c004142003-10-07 11:33:24 +00007160 /*
7161 * 4.16
7162 */
7163 if ((cur->parent != NULL) &&
7164 (xmlStrEqual
7165 (cur->parent->name, BAD_CAST "anyName"))) {
7166 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7167 xmlRelaxNGCleanupTree(ctxt, cur);
7168 ctxt->flags = oldflags;
7169 goto skip_children;
7170 } else if ((cur->parent != NULL) &&
7171 (xmlStrEqual
7172 (cur->parent->name, BAD_CAST "nsName"))) {
7173 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7174 xmlRelaxNGCleanupTree(ctxt, cur);
7175 ctxt->flags = oldflags;
7176 goto skip_children;
7177 }
7178 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7179 /*
7180 * 4.16
7181 */
7182 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7183 xmlRngPErr(ctxt, cur,
7184 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7185 "Found anyName/except//anyName forbidden construct\n",
7186 NULL, NULL);
7187 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7188 xmlRngPErr(ctxt, cur,
7189 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7190 "Found nsName/except//anyName forbidden construct\n",
7191 NULL, NULL);
7192 }
7193 }
7194 /*
7195 * Thisd is not an else since "include" is transformed
7196 * into a div
7197 */
7198 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7199 xmlChar *ns;
7200 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007201
Daniel Veillard4c004142003-10-07 11:33:24 +00007202 /*
7203 * implements rule 4.11
7204 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007205
Daniel Veillard4c004142003-10-07 11:33:24 +00007206 ns = xmlGetProp(cur, BAD_CAST "ns");
7207
7208 child = cur->children;
7209 ins = cur;
7210 while (child != NULL) {
7211 if (ns != NULL) {
7212 if (!xmlHasProp(child, BAD_CAST "ns")) {
7213 xmlSetProp(child, BAD_CAST "ns", ns);
7214 }
7215 }
7216 tmp = child->next;
7217 xmlUnlinkNode(child);
7218 ins = xmlAddNextSibling(ins, child);
7219 child = tmp;
7220 }
7221 if (ns != NULL)
7222 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007223 /*
7224 * Since we are about to delete cur, if it's nsDef is non-NULL we
7225 * need to preserve it (it contains the ns definitions for the
7226 * children we just moved). We'll just stick it on to the end
7227 * of cur->parent's list, since it's never going to be re-serialized
7228 * (bug 143738).
7229 */
7230 if (cur->nsDef != NULL) {
7231 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7232 while (parDef->next != NULL)
7233 parDef = parDef->next;
7234 parDef->next = cur->nsDef;
7235 cur->nsDef = NULL;
7236 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007237 delete = cur;
7238 goto skip_children;
7239 }
7240 }
7241 }
7242 /*
7243 * Simplification 4.2 whitespaces
7244 */
7245 else if ((cur->type == XML_TEXT_NODE) ||
7246 (cur->type == XML_CDATA_SECTION_NODE)) {
7247 if (IS_BLANK_NODE(cur)) {
7248 if (cur->parent->type == XML_ELEMENT_NODE) {
7249 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7250 &&
7251 (!xmlStrEqual
7252 (cur->parent->name, BAD_CAST "param")))
7253 delete = cur;
7254 } else {
7255 delete = cur;
7256 goto skip_children;
7257 }
7258 }
7259 } else {
7260 delete = cur;
7261 goto skip_children;
7262 }
7263
7264 /*
7265 * Skip to next node
7266 */
7267 if (cur->children != NULL) {
7268 if ((cur->children->type != XML_ENTITY_DECL) &&
7269 (cur->children->type != XML_ENTITY_REF_NODE) &&
7270 (cur->children->type != XML_ENTITY_NODE)) {
7271 cur = cur->children;
7272 continue;
7273 }
7274 }
7275 skip_children:
7276 if (cur->next != NULL) {
7277 cur = cur->next;
7278 continue;
7279 }
7280
7281 do {
7282 cur = cur->parent;
7283 if (cur == NULL)
7284 break;
7285 if (cur == root) {
7286 cur = NULL;
7287 break;
7288 }
7289 if (cur->next != NULL) {
7290 cur = cur->next;
7291 break;
7292 }
7293 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007294 }
7295 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007296 xmlUnlinkNode(delete);
7297 xmlFreeNode(delete);
7298 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007299 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007300}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007301
Daniel Veillardc5312d72003-02-21 17:14:10 +00007302/**
7303 * xmlRelaxNGCleanupDoc:
7304 * @ctxt: a Relax-NG parser context
7305 * @doc: an xmldocPtr document pointer
7306 *
7307 * Cleanup the document from unwanted nodes for parsing, resolve
7308 * Include and externalRef lookups.
7309 *
7310 * Returns the cleaned up document or NULL in case of error
7311 */
7312static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007313xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7314{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007315 xmlNodePtr root;
7316
7317 /*
7318 * Extract the root
7319 */
7320 root = xmlDocGetRootElement(doc);
7321 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007322 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7323 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007324 return (NULL);
7325 }
7326 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007327 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007328}
7329
7330/**
7331 * xmlRelaxNGParse:
7332 * @ctxt: a Relax-NG parser context
7333 *
7334 * parse a schema definition resource and build an internal
7335 * XML Shema struture which can be used to validate instances.
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007336 *
7337 * Returns the internal XML RelaxNG structure built from the resource or
7338 * NULL in case of error
7339 */
7340xmlRelaxNGPtr
7341xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7342{
7343 xmlRelaxNGPtr ret = NULL;
7344 xmlDocPtr doc;
7345 xmlNodePtr root;
7346
7347 xmlRelaxNGInitTypes();
7348
7349 if (ctxt == NULL)
7350 return (NULL);
7351
7352 /*
7353 * First step is to parse the input document into an DOM/Infoset
7354 */
7355 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007356 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007357 if (doc == NULL) {
7358 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7359 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7360 NULL);
7361 return (NULL);
7362 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007363 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007364 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007365 if (doc == NULL) {
7366 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7367 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7368 NULL);
7369 return (NULL);
7370 }
7371 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7372 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007373 } else if (ctxt->document != NULL) {
7374 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007375 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007376 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7377 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7378 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007379 }
7380 ctxt->document = doc;
7381
7382 /*
7383 * Some preprocessing of the document content
7384 */
7385 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7386 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007387 xmlFreeDoc(ctxt->document);
7388 ctxt->document = NULL;
7389 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007390 }
7391
Daniel Veillard6eadf632003-01-23 18:29:16 +00007392 /*
7393 * Then do the parsing for good
7394 */
7395 root = xmlDocGetRootElement(doc);
7396 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007397 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7398 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7399 ctxt->URL, NULL);
7400 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007401 return (NULL);
7402 }
7403 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007404 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007405 xmlFreeDoc(doc);
7406 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007407 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007408
7409 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007410 * Check the ref/defines links
7411 */
7412 /*
7413 * try to preprocess interleaves
7414 */
7415 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007416 xmlHashScan(ctxt->interleaves,
7417 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007418 }
7419
7420 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007421 * if there was a parsing error return NULL
7422 */
7423 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007424 xmlRelaxNGFree(ret);
7425 ctxt->document = NULL;
7426 xmlFreeDoc(doc);
7427 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007428 }
7429
7430 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007431 * try to compile (parts of) the schemas
7432 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007433 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7434 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007435 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007436
Daniel Veillard4c004142003-10-07 11:33:24 +00007437 def = xmlRelaxNGNewDefine(ctxt, NULL);
7438 if (def != NULL) {
7439 def->type = XML_RELAXNG_START;
7440 def->content = ret->topgrammar->start;
7441 ret->topgrammar->start = def;
7442 }
7443 }
7444 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007445 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007446
7447 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007448 * Transfer the pointer for cleanup at the schema level.
7449 */
7450 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007451 ctxt->document = NULL;
7452 ret->documents = ctxt->documents;
7453 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007454
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007455 ret->includes = ctxt->includes;
7456 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007457 ret->defNr = ctxt->defNr;
7458 ret->defTab = ctxt->defTab;
7459 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007460 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007461 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007462
7463 return (ret);
7464}
Daniel Veillard4c004142003-10-07 11:33:24 +00007465
Daniel Veillard6eadf632003-01-23 18:29:16 +00007466/**
7467 * xmlRelaxNGSetParserErrors:
7468 * @ctxt: a Relax-NG validation context
7469 * @err: the error callback
7470 * @warn: the warning callback
7471 * @ctx: contextual data for the callbacks
7472 *
7473 * Set the callback functions used to handle errors for a validation context
7474 */
7475void
7476xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007477 xmlRelaxNGValidityErrorFunc err,
7478 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7479{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007480 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007481 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007482 ctxt->error = err;
7483 ctxt->warning = warn;
Daniel Veillardb30ca312005-09-04 13:50:03 +00007484 ctxt->serror = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007485 ctxt->userData = ctx;
7486}
Daniel Veillard409a8142003-07-18 15:16:57 +00007487
7488/**
7489 * xmlRelaxNGGetParserErrors:
7490 * @ctxt: a Relax-NG validation context
7491 * @err: the error callback result
7492 * @warn: the warning callback result
7493 * @ctx: contextual data for the callbacks result
7494 *
7495 * Get the callback information used to handle errors for a validation context
7496 *
7497 * Returns -1 in case of failure, 0 otherwise.
7498 */
7499int
7500xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007501 xmlRelaxNGValidityErrorFunc * err,
7502 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7503{
Daniel Veillard409a8142003-07-18 15:16:57 +00007504 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007505 return (-1);
7506 if (err != NULL)
7507 *err = ctxt->error;
7508 if (warn != NULL)
7509 *warn = ctxt->warning;
7510 if (ctx != NULL)
7511 *ctx = ctxt->userData;
7512 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007513}
7514
Kasimier T. Buchcika930fbe2006-01-09 16:28:20 +00007515void
7516xmlRelaxNGSetParserStructuredErrors(
7517 xmlRelaxNGParserCtxtPtr ctxt,
7518 xmlStructuredErrorFunc serror,
7519 void *ctx)
7520{
7521 if (ctxt == NULL)
7522 return;
7523 ctxt->serror = serror;
7524 ctxt->error = NULL;
7525 ctxt->warning = NULL;
7526 ctxt->userData = ctx;
7527}
7528
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007529#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007530
Daniel Veillard6eadf632003-01-23 18:29:16 +00007531/************************************************************************
7532 * *
7533 * Dump back a compiled form *
7534 * *
7535 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007536static void xmlRelaxNGDumpDefine(FILE * output,
7537 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007538
7539/**
7540 * xmlRelaxNGDumpDefines:
7541 * @output: the file output
7542 * @defines: a list of define structures
7543 *
7544 * Dump a RelaxNG structure back
7545 */
7546static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007547xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7548{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007549 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007550 xmlRelaxNGDumpDefine(output, defines);
7551 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007552 }
7553}
7554
7555/**
7556 * xmlRelaxNGDumpDefine:
7557 * @output: the file output
7558 * @define: a define structure
7559 *
7560 * Dump a RelaxNG structure back
7561 */
7562static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007563xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7564{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007565 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007566 return;
7567 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007568 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007569 fprintf(output, "<empty/>\n");
7570 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007571 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007572 fprintf(output, "<notAllowed/>\n");
7573 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007574 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007575 fprintf(output, "<text/>\n");
7576 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007577 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007578 fprintf(output, "<element>\n");
7579 if (define->name != NULL) {
7580 fprintf(output, "<name");
7581 if (define->ns != NULL)
7582 fprintf(output, " ns=\"%s\"", define->ns);
7583 fprintf(output, ">%s</name>\n", define->name);
7584 }
7585 xmlRelaxNGDumpDefines(output, define->attrs);
7586 xmlRelaxNGDumpDefines(output, define->content);
7587 fprintf(output, "</element>\n");
7588 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007589 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007590 fprintf(output, "<list>\n");
7591 xmlRelaxNGDumpDefines(output, define->content);
7592 fprintf(output, "</list>\n");
7593 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007594 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007595 fprintf(output, "<oneOrMore>\n");
7596 xmlRelaxNGDumpDefines(output, define->content);
7597 fprintf(output, "</oneOrMore>\n");
7598 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007599 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007600 fprintf(output, "<zeroOrMore>\n");
7601 xmlRelaxNGDumpDefines(output, define->content);
7602 fprintf(output, "</zeroOrMore>\n");
7603 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007604 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007605 fprintf(output, "<choice>\n");
7606 xmlRelaxNGDumpDefines(output, define->content);
7607 fprintf(output, "</choice>\n");
7608 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007609 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007610 fprintf(output, "<group>\n");
7611 xmlRelaxNGDumpDefines(output, define->content);
7612 fprintf(output, "</group>\n");
7613 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007614 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007615 fprintf(output, "<interleave>\n");
7616 xmlRelaxNGDumpDefines(output, define->content);
7617 fprintf(output, "</interleave>\n");
7618 break;
7619 case XML_RELAXNG_OPTIONAL:
7620 fprintf(output, "<optional>\n");
7621 xmlRelaxNGDumpDefines(output, define->content);
7622 fprintf(output, "</optional>\n");
7623 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007624 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007625 fprintf(output, "<attribute>\n");
7626 xmlRelaxNGDumpDefines(output, define->content);
7627 fprintf(output, "</attribute>\n");
7628 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007629 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007630 fprintf(output, "<define");
7631 if (define->name != NULL)
7632 fprintf(output, " name=\"%s\"", define->name);
7633 fprintf(output, ">\n");
7634 xmlRelaxNGDumpDefines(output, define->content);
7635 fprintf(output, "</define>\n");
7636 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007637 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007638 fprintf(output, "<ref");
7639 if (define->name != NULL)
7640 fprintf(output, " name=\"%s\"", define->name);
7641 fprintf(output, ">\n");
7642 xmlRelaxNGDumpDefines(output, define->content);
7643 fprintf(output, "</ref>\n");
7644 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007645 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007646 fprintf(output, "<parentRef");
7647 if (define->name != NULL)
7648 fprintf(output, " name=\"%s\"", define->name);
7649 fprintf(output, ">\n");
7650 xmlRelaxNGDumpDefines(output, define->content);
7651 fprintf(output, "</parentRef>\n");
7652 break;
7653 case XML_RELAXNG_EXTERNALREF:
7654 fprintf(output, "<externalRef>");
7655 xmlRelaxNGDumpDefines(output, define->content);
7656 fprintf(output, "</externalRef>\n");
7657 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007658 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007659 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007660 TODO break;
7661 case XML_RELAXNG_START:
7662 case XML_RELAXNG_EXCEPT:
7663 case XML_RELAXNG_PARAM:
7664 TODO break;
7665 case XML_RELAXNG_NOOP:
7666 xmlRelaxNGDumpDefines(output, define->content);
7667 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007668 }
7669}
Daniel Veillard4c004142003-10-07 11:33:24 +00007670
Daniel Veillard6eadf632003-01-23 18:29:16 +00007671/**
7672 * xmlRelaxNGDumpGrammar:
7673 * @output: the file output
7674 * @grammar: a grammar structure
7675 * @top: is this a top grammar
7676 *
7677 * Dump a RelaxNG structure back
7678 */
7679static void
7680xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7681{
7682 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007683 return;
7684
Daniel Veillard6eadf632003-01-23 18:29:16 +00007685 fprintf(output, "<grammar");
7686 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007687 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7688 switch (grammar->combine) {
7689 case XML_RELAXNG_COMBINE_UNDEFINED:
7690 break;
7691 case XML_RELAXNG_COMBINE_CHOICE:
7692 fprintf(output, " combine=\"choice\"");
7693 break;
7694 case XML_RELAXNG_COMBINE_INTERLEAVE:
7695 fprintf(output, " combine=\"interleave\"");
7696 break;
7697 default:
7698 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007699 }
7700 fprintf(output, ">\n");
7701 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007702 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007703 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007704 fprintf(output, "<start>\n");
7705 xmlRelaxNGDumpDefine(output, grammar->start);
7706 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007707 }
7708 /* TODO ? Dump the defines ? */
7709 fprintf(output, "</grammar>\n");
7710}
7711
7712/**
7713 * xmlRelaxNGDump:
7714 * @output: the file output
7715 * @schema: a schema structure
7716 *
7717 * Dump a RelaxNG structure back
7718 */
7719void
7720xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7721{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007722 if (output == NULL)
7723 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007724 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007725 fprintf(output, "RelaxNG empty or failed to compile\n");
7726 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007727 }
7728 fprintf(output, "RelaxNG: ");
7729 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007730 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007731 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007732 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007733 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007734 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007735 }
7736 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007737 fprintf(output, "RelaxNG has no top grammar\n");
7738 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007739 }
7740 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7741}
7742
Daniel Veillardfebcca42003-02-16 15:44:18 +00007743/**
7744 * xmlRelaxNGDumpTree:
7745 * @output: the file output
7746 * @schema: a schema structure
7747 *
7748 * Dump the transformed RelaxNG tree.
7749 */
7750void
7751xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7752{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007753 if (output == NULL)
7754 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007755 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007756 fprintf(output, "RelaxNG empty or failed to compile\n");
7757 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007758 }
7759 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007760 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007761 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007762 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007763 }
7764}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007765#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007766
Daniel Veillard6eadf632003-01-23 18:29:16 +00007767/************************************************************************
7768 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007769 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007770 * *
7771 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007772static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7773 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007774
7775/**
7776 * xmlRelaxNGValidateCompiledCallback:
7777 * @exec: the regular expression instance
7778 * @token: the token which matched
7779 * @transdata: callback data, the define for the subelement if available
7780 @ @inputdata: callback data, the Relax NG validation context
7781 *
7782 * Handle the callback and if needed validate the element children.
7783 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007784static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007785xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007786 const xmlChar * token,
7787 void *transdata, void *inputdata)
7788{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007789 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7790 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7791 int ret;
7792
7793#ifdef DEBUG_COMPILE
7794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007795 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007796#endif
7797 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007798 fprintf(stderr, "callback on %s missing context\n", token);
7799 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7800 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7801 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007802 }
7803 if (define == NULL) {
7804 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007805 return;
7806 fprintf(stderr, "callback on %s missing define\n", token);
7807 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7808 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7809 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007810 }
7811 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007812 fprintf(stderr, "callback on %s missing info\n", token);
7813 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7814 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7815 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007816 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007817 fprintf(stderr, "callback on %s define is not element\n", token);
7818 if (ctxt->errNo == XML_RELAXNG_OK)
7819 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7820 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007821 }
7822 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007823 if (ret != 0)
7824 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007825}
7826
7827/**
7828 * xmlRelaxNGValidateCompiledContent:
7829 * @ctxt: the RelaxNG validation context
7830 * @regexp: the regular expression as compiled
7831 * @content: list of children to test against the regexp
7832 *
7833 * Validate the content model of an element or start using the regexp
7834 *
7835 * Returns 0 in case of success, -1 in case of error.
7836 */
7837static int
7838xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007839 xmlRegexpPtr regexp, xmlNodePtr content)
7840{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007841 xmlRegExecCtxtPtr exec;
7842 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007843 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007844 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007845
7846 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007847 return (-1);
7848 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007849 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007850 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007851 cur = content;
7852 while (cur != NULL) {
7853 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007854 switch (cur->type) {
7855 case XML_TEXT_NODE:
7856 case XML_CDATA_SECTION_NODE:
7857 if (xmlIsBlankNode(cur))
7858 break;
7859 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7860 if (ret < 0) {
7861 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7862 cur->parent->name);
7863 }
7864 break;
7865 case XML_ELEMENT_NODE:
7866 if (cur->ns != NULL) {
7867 ret = xmlRegExecPushString2(exec, cur->name,
7868 cur->ns->href, ctxt);
7869 } else {
7870 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7871 }
7872 if (ret < 0) {
7873 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7874 }
7875 break;
7876 default:
7877 break;
7878 }
7879 if (ret < 0)
7880 break;
7881 /*
7882 * Switch to next element
7883 */
7884 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007885 }
7886 ret = xmlRegExecPushString(exec, NULL, NULL);
7887 if (ret == 1) {
7888 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007889 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007890 } else if (ret == 0) {
7891 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007892 * TODO: get some of the names needed to exit the current state of exec
7893 */
7894 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7895 ret = -1;
7896 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7897 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007898 } else {
7899 ret = -1;
7900 }
7901 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007902 /*
7903 * There might be content model errors outside of the pure
7904 * regexp validation, e.g. for attribute values.
7905 */
7906 if ((ret == 0) && (ctxt->perr != 0)) {
7907 ret = ctxt->perr;
7908 }
7909 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007910 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007911}
7912
7913/************************************************************************
7914 * *
7915 * Progressive validation of when possible *
7916 * *
7917 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007918static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7919 xmlRelaxNGDefinePtr defines);
7920static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007921 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007922static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007923
7924/**
7925 * xmlRelaxNGElemPush:
7926 * @ctxt: the validation context
7927 * @exec: the regexp runtime for the new content model
7928 *
7929 * Push a new regexp for the current node content model on the stack
7930 *
7931 * Returns 0 in case of success and -1 in case of error.
7932 */
7933static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007934xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7935{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007936 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007937 ctxt->elemMax = 10;
7938 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7939 sizeof
7940 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007941 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007942 xmlRngVErrMemory(ctxt, "validating\n");
7943 return (-1);
7944 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007945 }
7946 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007947 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007948 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007949 ctxt->elemMax *
7950 sizeof
7951 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007952 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007953 xmlRngVErrMemory(ctxt, "validating\n");
7954 return (-1);
7955 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007956 }
7957 ctxt->elemTab[ctxt->elemNr++] = exec;
7958 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007959 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007960}
7961
7962/**
7963 * xmlRelaxNGElemPop:
7964 * @ctxt: the validation context
7965 *
7966 * Pop the regexp of the current node content model from the stack
7967 *
7968 * Returns the exec or NULL if empty
7969 */
7970static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007971xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7972{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007973 xmlRegExecCtxtPtr ret;
7974
Daniel Veillard4c004142003-10-07 11:33:24 +00007975 if (ctxt->elemNr <= 0)
7976 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007977 ctxt->elemNr--;
7978 ret = ctxt->elemTab[ctxt->elemNr];
7979 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007980 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007981 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7982 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007983 ctxt->elem = NULL;
7984 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007985}
7986
7987/**
7988 * xmlRelaxNGValidateProgressiveCallback:
7989 * @exec: the regular expression instance
7990 * @token: the token which matched
7991 * @transdata: callback data, the define for the subelement if available
7992 @ @inputdata: callback data, the Relax NG validation context
7993 *
7994 * Handle the callback and if needed validate the element children.
7995 * some of the in/out informations are passed via the context in @inputdata.
7996 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007997static void
7998xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7999 ATTRIBUTE_UNUSED,
8000 const xmlChar * token,
8001 void *transdata, void *inputdata)
8002{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008003 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
8004 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008005 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008006 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00008007 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008008
8009#ifdef DEBUG_PROGRESSIVE
8010 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00008011 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008012#endif
8013 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008014 fprintf(stderr, "callback on %s missing context\n", token);
8015 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008016 }
8017 ctxt->pstate = 1;
8018 if (define == NULL) {
8019 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00008020 return;
8021 fprintf(stderr, "callback on %s missing define\n", token);
8022 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8023 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8024 ctxt->pstate = -1;
8025 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008026 }
8027 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008028 fprintf(stderr, "callback on %s missing info\n", token);
8029 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8030 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8031 ctxt->pstate = -1;
8032 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008033 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008034 fprintf(stderr, "callback on %s define is not element\n", token);
8035 if (ctxt->errNo == XML_RELAXNG_OK)
8036 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8037 ctxt->pstate = -1;
8038 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008039 }
8040 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008041 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8042 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8043 xmlRelaxNGDumpValidError(ctxt);
8044 ctxt->pstate = -1;
8045 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008046 }
8047 if (define->contModel == NULL) {
8048 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008049 * this node cannot be validated in a streamable fashion
8050 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00008051#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008052 xmlGenericError(xmlGenericErrorContext,
8053 "Element '%s' validation is not streamable\n",
8054 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008055#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008056 ctxt->pstate = 0;
8057 ctxt->pdef = define;
8058 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008059 }
8060 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008061 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008062 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008063 ctxt->pstate = -1;
8064 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008065 }
8066 xmlRelaxNGElemPush(ctxt, exec);
8067
8068 /*
8069 * Validate the attributes part of the content.
8070 */
8071 state = xmlRelaxNGNewValidState(ctxt, node);
8072 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008073 ctxt->pstate = -1;
8074 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008075 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008076 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008077 ctxt->state = state;
8078 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008079 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8080 if (ret != 0) {
8081 ctxt->pstate = -1;
8082 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8083 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008084 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008085 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008086 ctxt->state->seq = NULL;
8087 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8088 if (ret != 0) {
8089 ctxt->pstate = -1;
8090 }
8091 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008092 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008093 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008094
8095 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008096
Daniel Veillard4c004142003-10-07 11:33:24 +00008097 for (i = 0; i < ctxt->states->nbState; i++) {
8098 state = ctxt->states->tabState[i];
8099 ctxt->state = state;
8100 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008101
Daniel Veillard4c004142003-10-07 11:33:24 +00008102 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8103 tmp = 0;
8104 break;
8105 }
8106 }
8107 if (tmp != 0) {
8108 /*
8109 * validation error, log the message for the "best" one
8110 */
8111 ctxt->flags |= FLAGS_IGNORABLE;
8112 xmlRelaxNGLogBestError(ctxt);
8113 }
8114 for (i = 0; i < ctxt->states->nbState; i++) {
8115 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8116 }
8117 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8118 ctxt->states = NULL;
8119 if ((ret == 0) && (tmp == -1))
8120 ctxt->pstate = -1;
8121 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008122 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008123 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008124 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8125 xmlRelaxNGDumpValidError(ctxt);
8126 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008127 }
8128 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008129}
8130
8131/**
8132 * xmlRelaxNGValidatePushElement:
8133 * @ctxt: the validation context
8134 * @doc: a document instance
8135 * @elem: an element instance
8136 *
8137 * Push a new element start on the RelaxNG validation stack.
8138 *
8139 * returns 1 if no validation problem was found or 0 if validating the
8140 * element requires a full node, and -1 in case of error.
8141 */
8142int
Daniel Veillard33300b42003-04-17 09:09:19 +00008143xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8144 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008145 xmlNodePtr elem)
8146{
8147 int ret = 1;
8148
8149 if ((ctxt == NULL) || (elem == NULL))
8150 return (-1);
8151
8152#ifdef DEBUG_PROGRESSIVE
8153 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8154#endif
8155 if (ctxt->elem == 0) {
8156 xmlRelaxNGPtr schema;
8157 xmlRelaxNGGrammarPtr grammar;
8158 xmlRegExecCtxtPtr exec;
8159 xmlRelaxNGDefinePtr define;
8160
8161 schema = ctxt->schema;
8162 if (schema == NULL) {
8163 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8164 return (-1);
8165 }
8166 grammar = schema->topgrammar;
8167 if ((grammar == NULL) || (grammar->start == NULL)) {
8168 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8169 return (-1);
8170 }
8171 define = grammar->start;
8172 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008173 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008174 return (0);
8175 }
8176 exec = xmlRegNewExecCtxt(define->contModel,
8177 xmlRelaxNGValidateProgressiveCallback,
8178 ctxt);
8179 if (exec == NULL) {
8180 return (-1);
8181 }
8182 xmlRelaxNGElemPush(ctxt, exec);
8183 }
8184 ctxt->pnode = elem;
8185 ctxt->pstate = 0;
8186 if (elem->ns != NULL) {
8187 ret =
8188 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8189 ctxt);
8190 } else {
8191 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8192 }
8193 if (ret < 0) {
8194 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8195 } else {
8196 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008197 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008198 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008199 ret = -1;
8200 else
8201 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008202 }
8203#ifdef DEBUG_PROGRESSIVE
8204 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008205 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8206 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008207#endif
8208 return (ret);
8209}
8210
8211/**
8212 * xmlRelaxNGValidatePushCData:
8213 * @ctxt: the RelaxNG validation context
8214 * @data: some character data read
8215 * @len: the lenght of the data
8216 *
8217 * check the CData parsed for validation in the current stack
8218 *
8219 * returns 1 if no validation problem was found or -1 otherwise
8220 */
8221int
8222xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008223 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008224{
8225 int ret = 1;
8226
8227 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8228 return (-1);
8229
8230#ifdef DEBUG_PROGRESSIVE
8231 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8232#endif
8233
8234 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008235 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008236 break;
8237 data++;
8238 }
8239 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008240 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008241
8242 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8243 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008244 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008245#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008246 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008247#endif
8248
Daniel Veillard4c004142003-10-07 11:33:24 +00008249 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008250 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008251 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008252}
8253
8254/**
8255 * xmlRelaxNGValidatePopElement:
8256 * @ctxt: the RelaxNG validation context
8257 * @doc: a document instance
8258 * @elem: an element instance
8259 *
8260 * Pop the element end from the RelaxNG validation stack.
8261 *
8262 * returns 1 if no validation problem was found or 0 otherwise
8263 */
8264int
8265xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8266 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008267 xmlNodePtr elem)
8268{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008269 int ret;
8270 xmlRegExecCtxtPtr exec;
8271
Daniel Veillard4c004142003-10-07 11:33:24 +00008272 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8273 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008274#ifdef DEBUG_PROGRESSIVE
8275 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8276#endif
8277 /*
8278 * verify that we reached a terminal state of the content model.
8279 */
8280 exec = xmlRelaxNGElemPop(ctxt);
8281 ret = xmlRegExecPushString(exec, NULL, NULL);
8282 if (ret == 0) {
8283 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008284 * TODO: get some of the names needed to exit the current state of exec
8285 */
8286 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8287 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008288 } else if (ret < 0) {
8289 ret = -1;
8290 } else {
8291 ret = 1;
8292 }
8293 xmlRegFreeExecCtxt(exec);
8294#ifdef DEBUG_PROGRESSIVE
8295 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008296 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8297 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008298#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008299 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008300}
8301
8302/**
8303 * xmlRelaxNGValidateFullElement:
8304 * @ctxt: the validation context
8305 * @doc: a document instance
8306 * @elem: an element instance
8307 *
8308 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8309 * 0 and the content of the node has been expanded.
8310 *
8311 * returns 1 if no validation problem was found or -1 in case of error.
8312 */
8313int
Daniel Veillard33300b42003-04-17 09:09:19 +00008314xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8315 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008316 xmlNodePtr elem)
8317{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008318 int ret;
8319 xmlRelaxNGValidStatePtr state;
8320
Daniel Veillard4c004142003-10-07 11:33:24 +00008321 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8322 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008323#ifdef DEBUG_PROGRESSIVE
8324 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8325#endif
8326 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8327 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008328 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008329 }
8330 state->seq = elem;
8331 ctxt->state = state;
8332 ctxt->errNo = XML_RELAXNG_OK;
8333 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008334 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8335 ret = -1;
8336 else
8337 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008338 xmlRelaxNGFreeValidState(ctxt, state);
8339 ctxt->state = NULL;
8340#ifdef DEBUG_PROGRESSIVE
8341 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008342 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8343 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008344#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008345 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008346}
8347
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008348/************************************************************************
8349 * *
8350 * Generic interpreted validation implementation *
8351 * *
8352 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008353static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8354 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008355
8356/**
8357 * xmlRelaxNGSkipIgnored:
8358 * @ctxt: a schema validation context
8359 * @node: the top node.
8360 *
8361 * Skip ignorable nodes in that context
8362 *
8363 * Returns the new sibling or NULL in case of error.
8364 */
8365static xmlNodePtr
8366xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008367 xmlNodePtr node)
8368{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008369 /*
8370 * TODO complete and handle entities
8371 */
8372 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008373 ((node->type == XML_COMMENT_NODE) ||
8374 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008375 (node->type == XML_XINCLUDE_START) ||
8376 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008377 (((node->type == XML_TEXT_NODE) ||
8378 (node->type == XML_CDATA_SECTION_NODE)) &&
8379 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8380 (IS_BLANK_NODE(node)))))) {
8381 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008382 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008383 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008384}
8385
8386/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008387 * xmlRelaxNGNormalize:
8388 * @ctxt: a schema validation context
8389 * @str: the string to normalize
8390 *
8391 * Implements the normalizeWhiteSpace( s ) function from
8392 * section 6.2.9 of the spec
8393 *
8394 * Returns the new string or NULL in case of error.
8395 */
8396static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008397xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8398{
Daniel Veillardedc91922003-01-26 00:52:04 +00008399 xmlChar *ret, *p;
8400 const xmlChar *tmp;
8401 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008402
Daniel Veillardedc91922003-01-26 00:52:04 +00008403 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008404 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008405 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008406 while (*tmp != 0)
8407 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008408 len = tmp - str;
8409
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008410 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008411 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008412 xmlRngVErrMemory(ctxt, "validating\n");
8413 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008414 }
8415 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008416 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008417 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008418 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008419 if (IS_BLANK_CH(*str)) {
8420 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008421 str++;
8422 if (*str == 0)
8423 break;
8424 *p++ = ' ';
8425 } else
8426 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008427 }
8428 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008429 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008430}
8431
8432/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008433 * xmlRelaxNGValidateDatatype:
8434 * @ctxt: a Relax-NG validation context
8435 * @value: the string value
8436 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008437 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008438 *
8439 * Validate the given value against the dataype
8440 *
8441 * Returns 0 if the validation succeeded or an error code.
8442 */
8443static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008444xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8445 const xmlChar * value,
8446 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8447{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008448 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008449 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008450 void *result = NULL;
8451 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008452
8453 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008454 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008455 }
8456 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008457 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008458 if ((define->attrs != NULL) &&
8459 (define->attrs->type == XML_RELAXNG_PARAM)) {
8460 ret =
8461 lib->check(lib->data, define->name, value, &result, node);
8462 } else {
8463 ret = lib->check(lib->data, define->name, value, NULL, node);
8464 }
8465 } else
8466 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008467 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008468 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8469 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8470 lib->freef(lib->data, result);
8471 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008472 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008473 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008474 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008475 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008476 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008477 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8478 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008479 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008480 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008481 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008482 if (lib->facet != NULL) {
8483 tmp = lib->facet(lib->data, define->name, cur->name,
8484 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008485 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008486 ret = -1;
8487 }
8488 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008489 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008490 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008491 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008492
Daniel Veillard4c004142003-10-07 11:33:24 +00008493 oldvalue = ctxt->state->value;
8494 oldendvalue = ctxt->state->endvalue;
8495 ctxt->state->value = (xmlChar *) value;
8496 ctxt->state->endvalue = NULL;
8497 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8498 ctxt->state->value = (xmlChar *) oldvalue;
8499 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008500 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008501 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008502 lib->freef(lib->data, result);
8503 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008504}
8505
8506/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008507 * xmlRelaxNGNextValue:
8508 * @ctxt: a Relax-NG validation context
8509 *
8510 * Skip to the next value when validating within a list
8511 *
8512 * Returns 0 if the operation succeeded or an error code.
8513 */
8514static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008515xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8516{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008517 xmlChar *cur;
8518
8519 cur = ctxt->state->value;
8520 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008521 ctxt->state->value = NULL;
8522 ctxt->state->endvalue = NULL;
8523 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008524 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008525 while (*cur != 0)
8526 cur++;
8527 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8528 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008529 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008530 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008531 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008532 ctxt->state->value = cur;
8533 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008534}
8535
8536/**
8537 * xmlRelaxNGValidateValueList:
8538 * @ctxt: a Relax-NG validation context
8539 * @defines: the list of definitions to verify
8540 *
8541 * Validate the given set of definitions for the current value
8542 *
8543 * Returns 0 if the validation succeeded or an error code.
8544 */
8545static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008546xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8547 xmlRelaxNGDefinePtr defines)
8548{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008549 int ret = 0;
8550
8551 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008552 ret = xmlRelaxNGValidateValue(ctxt, defines);
8553 if (ret != 0)
8554 break;
8555 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008556 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008557 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008558}
8559
8560/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008561 * xmlRelaxNGValidateValue:
8562 * @ctxt: a Relax-NG validation context
8563 * @define: the definition to verify
8564 *
8565 * Validate the given definition for the current value
8566 *
8567 * Returns 0 if the validation succeeded or an error code.
8568 */
8569static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008570xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8571 xmlRelaxNGDefinePtr define)
8572{
Daniel Veillardedc91922003-01-26 00:52:04 +00008573 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008574 xmlChar *value;
8575
8576 value = ctxt->state->value;
8577 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008578 case XML_RELAXNG_EMPTY:{
8579 if ((value != NULL) && (value[0] != 0)) {
8580 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008581
William M. Brack76e95df2003-10-18 16:20:14 +00008582 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008583 idx++;
8584 if (value[idx] != 0)
8585 ret = -1;
8586 }
8587 break;
8588 }
8589 case XML_RELAXNG_TEXT:
8590 break;
8591 case XML_RELAXNG_VALUE:{
8592 if (!xmlStrEqual(value, define->value)) {
8593 if (define->name != NULL) {
8594 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008595
Daniel Veillard4c004142003-10-07 11:33:24 +00008596 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8597 if ((lib != NULL) && (lib->comp != NULL)) {
8598 ret = lib->comp(lib->data, define->name,
8599 define->value, define->node,
8600 (void *) define->attrs,
8601 value, ctxt->state->node);
8602 } else
8603 ret = -1;
8604 if (ret < 0) {
8605 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8606 define->name);
8607 return (-1);
8608 } else if (ret == 1) {
8609 ret = 0;
8610 } else {
8611 ret = -1;
8612 }
8613 } else {
8614 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008615
Daniel Veillard4c004142003-10-07 11:33:24 +00008616 /*
8617 * TODO: trivial optimizations are possible by
8618 * computing at compile-time
8619 */
8620 nval = xmlRelaxNGNormalize(ctxt, define->value);
8621 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008622
Daniel Veillard4c004142003-10-07 11:33:24 +00008623 if ((nval == NULL) || (nvalue == NULL) ||
8624 (!xmlStrEqual(nval, nvalue)))
8625 ret = -1;
8626 if (nval != NULL)
8627 xmlFree(nval);
8628 if (nvalue != NULL)
8629 xmlFree(nvalue);
8630 }
8631 }
8632 if (ret == 0)
8633 xmlRelaxNGNextValue(ctxt);
8634 break;
8635 }
8636 case XML_RELAXNG_DATATYPE:{
8637 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8638 ctxt->state->seq);
8639 if (ret == 0)
8640 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008641
Daniel Veillard4c004142003-10-07 11:33:24 +00008642 break;
8643 }
8644 case XML_RELAXNG_CHOICE:{
8645 xmlRelaxNGDefinePtr list = define->content;
8646 xmlChar *oldvalue;
8647
8648 oldflags = ctxt->flags;
8649 ctxt->flags |= FLAGS_IGNORABLE;
8650
8651 oldvalue = ctxt->state->value;
8652 while (list != NULL) {
8653 ret = xmlRelaxNGValidateValue(ctxt, list);
8654 if (ret == 0) {
8655 break;
8656 }
8657 ctxt->state->value = oldvalue;
8658 list = list->next;
8659 }
8660 ctxt->flags = oldflags;
8661 if (ret != 0) {
8662 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8663 xmlRelaxNGDumpValidError(ctxt);
8664 } else {
8665 if (ctxt->errNr > 0)
8666 xmlRelaxNGPopErrors(ctxt, 0);
8667 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008668 break;
8669 }
8670 case XML_RELAXNG_LIST:{
8671 xmlRelaxNGDefinePtr list = define->content;
8672 xmlChar *oldvalue, *oldend, *val, *cur;
8673
Daniel Veillard416589a2003-02-17 17:25:42 +00008674#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008675 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008676#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008677
Daniel Veillard4c004142003-10-07 11:33:24 +00008678 oldvalue = ctxt->state->value;
8679 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008680
Daniel Veillard4c004142003-10-07 11:33:24 +00008681 val = xmlStrdup(oldvalue);
8682 if (val == NULL) {
8683 val = xmlStrdup(BAD_CAST "");
8684 }
8685 if (val == NULL) {
8686 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8687 return (-1);
8688 }
8689 cur = val;
8690 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008691 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008692 *cur = 0;
8693 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008694#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008695 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008696#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008697 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008698 *cur++ = 0;
8699 } else
8700 cur++;
8701 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008702#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008703 xmlGenericError(xmlGenericErrorContext,
8704 "list value: '%s' found %d items\n",
8705 oldvalue, nb_values);
8706 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008707#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008708 ctxt->state->endvalue = cur;
8709 cur = val;
8710 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8711 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008712
Daniel Veillard4c004142003-10-07 11:33:24 +00008713 ctxt->state->value = cur;
8714
8715 while (list != NULL) {
8716 if (ctxt->state->value == ctxt->state->endvalue)
8717 ctxt->state->value = NULL;
8718 ret = xmlRelaxNGValidateValue(ctxt, list);
8719 if (ret != 0) {
8720#ifdef DEBUG_LIST
8721 xmlGenericError(xmlGenericErrorContext,
8722 "Failed to validate value: '%s' with %d rule\n",
8723 ctxt->state->value, nb_values);
8724#endif
8725 break;
8726 }
8727#ifdef DEBUG_LIST
8728 nb_values++;
8729#endif
8730 list = list->next;
8731 }
8732
8733 if ((ret == 0) && (ctxt->state->value != NULL) &&
8734 (ctxt->state->value != ctxt->state->endvalue)) {
8735 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8736 ctxt->state->value);
8737 ret = -1;
8738 }
8739 xmlFree(val);
8740 ctxt->state->value = oldvalue;
8741 ctxt->state->endvalue = oldend;
8742 break;
8743 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008744 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008745 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8746 if (ret != 0) {
8747 break;
8748 }
8749 /* no break on purpose */
8750 case XML_RELAXNG_ZEROORMORE:{
8751 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008752
Daniel Veillard4c004142003-10-07 11:33:24 +00008753 oldflags = ctxt->flags;
8754 ctxt->flags |= FLAGS_IGNORABLE;
8755 cur = ctxt->state->value;
8756 temp = NULL;
8757 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8758 (temp != cur)) {
8759 temp = cur;
8760 ret =
8761 xmlRelaxNGValidateValueList(ctxt, define->content);
8762 if (ret != 0) {
8763 ctxt->state->value = temp;
8764 ret = 0;
8765 break;
8766 }
8767 cur = ctxt->state->value;
8768 }
8769 ctxt->flags = oldflags;
8770 if (ret != 0) {
8771 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8772 xmlRelaxNGDumpValidError(ctxt);
8773 } else {
8774 if (ctxt->errNr > 0)
8775 xmlRelaxNGPopErrors(ctxt, 0);
8776 }
8777 break;
8778 }
8779 case XML_RELAXNG_EXCEPT:{
8780 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008781
Daniel Veillard4c004142003-10-07 11:33:24 +00008782 list = define->content;
8783 while (list != NULL) {
8784 ret = xmlRelaxNGValidateValue(ctxt, list);
8785 if (ret == 0) {
8786 ret = -1;
8787 break;
8788 } else
8789 ret = 0;
8790 list = list->next;
8791 }
8792 break;
8793 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008794 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008795 case XML_RELAXNG_GROUP:{
8796 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008797
Daniel Veillard4c004142003-10-07 11:33:24 +00008798 list = define->content;
8799 while (list != NULL) {
8800 ret = xmlRelaxNGValidateValue(ctxt, list);
8801 if (ret != 0) {
8802 ret = -1;
8803 break;
8804 } else
8805 ret = 0;
8806 list = list->next;
8807 }
8808 break;
8809 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008810 case XML_RELAXNG_REF:
8811 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008812 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8813 break;
8814 default:
8815 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008816 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008817 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008818}
8819
8820/**
8821 * xmlRelaxNGValidateValueContent:
8822 * @ctxt: a Relax-NG validation context
8823 * @defines: the list of definitions to verify
8824 *
8825 * Validate the given definitions for the current value
8826 *
8827 * Returns 0 if the validation succeeded or an error code.
8828 */
8829static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008830xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8831 xmlRelaxNGDefinePtr defines)
8832{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008833 int ret = 0;
8834
8835 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008836 ret = xmlRelaxNGValidateValue(ctxt, defines);
8837 if (ret != 0)
8838 break;
8839 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008840 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008841 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008842}
8843
8844/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008845 * xmlRelaxNGAttributeMatch:
8846 * @ctxt: a Relax-NG validation context
8847 * @define: the definition to check
8848 * @prop: the attribute
8849 *
8850 * Check if the attribute matches the definition nameClass
8851 *
8852 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8853 */
8854static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008855xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8856 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8857{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008858 int ret;
8859
8860 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008861 if (!xmlStrEqual(define->name, prop->name))
8862 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008863 }
8864 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008865 if (define->ns[0] == 0) {
8866 if (prop->ns != NULL)
8867 return (0);
8868 } else {
8869 if ((prop->ns == NULL) ||
8870 (!xmlStrEqual(define->ns, prop->ns->href)))
8871 return (0);
8872 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008873 }
8874 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008875 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008876 define = define->nameClass;
8877 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008878 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008879
Daniel Veillard4c004142003-10-07 11:33:24 +00008880 list = define->content;
8881 while (list != NULL) {
8882 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8883 if (ret == 1)
8884 return (0);
8885 if (ret < 0)
8886 return (ret);
8887 list = list->next;
8888 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008889 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008890 TODO}
8891 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008892}
8893
8894/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008895 * xmlRelaxNGValidateAttribute:
8896 * @ctxt: a Relax-NG validation context
8897 * @define: the definition to verify
8898 *
8899 * Validate the given attribute definition for that node
8900 *
8901 * Returns 0 if the validation succeeded or an error code.
8902 */
8903static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008904xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8905 xmlRelaxNGDefinePtr define)
8906{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008907 int ret = 0, i;
8908 xmlChar *value, *oldvalue;
8909 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008910 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008911
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008912 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008913 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008914 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008915 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8916 tmp = ctxt->state->attrs[i];
8917 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8918 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8919 (tmp->ns == NULL)) ||
8920 ((tmp->ns != NULL) &&
8921 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8922 prop = tmp;
8923 break;
8924 }
8925 }
8926 }
8927 if (prop != NULL) {
8928 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8929 oldvalue = ctxt->state->value;
8930 oldseq = ctxt->state->seq;
8931 ctxt->state->seq = (xmlNodePtr) prop;
8932 ctxt->state->value = value;
8933 ctxt->state->endvalue = NULL;
8934 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8935 if (ctxt->state->value != NULL)
8936 value = ctxt->state->value;
8937 if (value != NULL)
8938 xmlFree(value);
8939 ctxt->state->value = oldvalue;
8940 ctxt->state->seq = oldseq;
8941 if (ret == 0) {
8942 /*
8943 * flag the attribute as processed
8944 */
8945 ctxt->state->attrs[i] = NULL;
8946 ctxt->state->nbAttrLeft--;
8947 }
8948 } else {
8949 ret = -1;
8950 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008951#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008952 xmlGenericError(xmlGenericErrorContext,
8953 "xmlRelaxNGValidateAttribute(%s): %d\n",
8954 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008955#endif
8956 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008957 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8958 tmp = ctxt->state->attrs[i];
8959 if ((tmp != NULL) &&
8960 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8961 prop = tmp;
8962 break;
8963 }
8964 }
8965 if (prop != NULL) {
8966 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8967 oldvalue = ctxt->state->value;
8968 oldseq = ctxt->state->seq;
8969 ctxt->state->seq = (xmlNodePtr) prop;
8970 ctxt->state->value = value;
8971 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8972 if (ctxt->state->value != NULL)
8973 value = ctxt->state->value;
8974 if (value != NULL)
8975 xmlFree(value);
8976 ctxt->state->value = oldvalue;
8977 ctxt->state->seq = oldseq;
8978 if (ret == 0) {
8979 /*
8980 * flag the attribute as processed
8981 */
8982 ctxt->state->attrs[i] = NULL;
8983 ctxt->state->nbAttrLeft--;
8984 }
8985 } else {
8986 ret = -1;
8987 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008988#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008989 if (define->ns != NULL) {
8990 xmlGenericError(xmlGenericErrorContext,
8991 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8992 define->ns, ret);
8993 } else {
8994 xmlGenericError(xmlGenericErrorContext,
8995 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8996 ret);
8997 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008998#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008999 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009000
9001 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009002}
9003
9004/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009005 * xmlRelaxNGValidateAttributeList:
9006 * @ctxt: a Relax-NG validation context
9007 * @define: the list of definition to verify
9008 *
9009 * Validate the given node against the list of attribute definitions
9010 *
9011 * Returns 0 if the validation succeeded or an error code.
9012 */
9013static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009014xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
9015 xmlRelaxNGDefinePtr defines)
9016{
Daniel Veillardce192eb2003-04-16 15:58:05 +00009017 int ret = 0, res;
9018 int needmore = 0;
9019 xmlRelaxNGDefinePtr cur;
9020
9021 cur = defines;
9022 while (cur != NULL) {
9023 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009024 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9025 ret = -1;
9026 } else
9027 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009028 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009029 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009030 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00009031 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009032 cur = defines;
9033 while (cur != NULL) {
9034 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009035 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9036 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9037 if (res < 0)
9038 ret = -1;
9039 } else {
9040 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9041 return (-1);
9042 }
9043 if (res == -1) /* continues on -2 */
9044 break;
9045 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009046 cur = cur->next;
9047 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009048
9049 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009050}
9051
9052/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009053 * xmlRelaxNGNodeMatchesList:
9054 * @node: the node
9055 * @list: a NULL terminated array of definitions
9056 *
9057 * Check if a node can be matched by one of the definitions
9058 *
9059 * Returns 1 if matches 0 otherwise
9060 */
9061static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009062xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9063{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009064 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009065 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009066
9067 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009068 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009069
9070 cur = list[i++];
9071 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009072 if ((node->type == XML_ELEMENT_NODE) &&
9073 (cur->type == XML_RELAXNG_ELEMENT)) {
9074 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9075 if (tmp == 1)
9076 return (1);
9077 } else if (((node->type == XML_TEXT_NODE) ||
9078 (node->type == XML_CDATA_SECTION_NODE)) &&
9079 (cur->type == XML_RELAXNG_TEXT)) {
9080 return (1);
9081 }
9082 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009083 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009084 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009085}
9086
9087/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009088 * xmlRelaxNGValidateInterleave:
9089 * @ctxt: a Relax-NG validation context
9090 * @define: the definition to verify
9091 *
9092 * Validate an interleave definition for a node.
9093 *
9094 * Returns 0 if the validation succeeded or an error code.
9095 */
9096static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009097xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9098 xmlRelaxNGDefinePtr define)
9099{
William M. Brack779af002003-08-01 15:55:39 +00009100 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009101 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009102 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009103
9104 xmlRelaxNGValidStatePtr oldstate;
9105 xmlRelaxNGPartitionPtr partitions;
9106 xmlRelaxNGInterleaveGroupPtr group = NULL;
9107 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9108 xmlNodePtr *list = NULL, *lasts = NULL;
9109
9110 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009111 partitions = (xmlRelaxNGPartitionPtr) define->data;
9112 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009113 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009114 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9115 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009116 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009117 /*
9118 * Optimizations for MIXED
9119 */
9120 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009121 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009122 ctxt->flags |= FLAGS_MIXED_CONTENT;
9123 if (nbgroups == 2) {
9124 /*
9125 * this is a pure <mixed> case
9126 */
9127 if (ctxt->state != NULL)
9128 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9129 ctxt->state->seq);
9130 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9131 ret = xmlRelaxNGValidateDefinition(ctxt,
9132 partitions->groups[1]->
9133 rule);
9134 else
9135 ret = xmlRelaxNGValidateDefinition(ctxt,
9136 partitions->groups[0]->
9137 rule);
9138 if (ret == 0) {
9139 if (ctxt->state != NULL)
9140 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9141 ctxt->state->
9142 seq);
9143 }
9144 ctxt->flags = oldflags;
9145 return (ret);
9146 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009147 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009148
9149 /*
9150 * Build arrays to store the first and last node of the chain
9151 * pertaining to each group
9152 */
9153 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9154 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009155 xmlRngVErrMemory(ctxt, "validating\n");
9156 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009157 }
9158 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9159 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9160 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009161 xmlRngVErrMemory(ctxt, "validating\n");
9162 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009163 }
9164 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9165
9166 /*
9167 * Walk the sequence of children finding the right group and
9168 * sorting them in sequences.
9169 */
9170 cur = ctxt->state->seq;
9171 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9172 start = cur;
9173 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009174 ctxt->state->seq = cur;
9175 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009176 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009177 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009178
Daniel Veillard4c004142003-10-07 11:33:24 +00009179 if ((cur->type == XML_TEXT_NODE) ||
9180 (cur->type == XML_CDATA_SECTION_NODE)) {
9181 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9182 NULL);
9183 } else if (cur->type == XML_ELEMENT_NODE) {
9184 if (cur->ns != NULL) {
9185 tmp = xmlHashLookup2(partitions->triage, cur->name,
9186 cur->ns->href);
9187 if (tmp == NULL)
9188 tmp = xmlHashLookup2(partitions->triage,
9189 BAD_CAST "#any",
9190 cur->ns->href);
9191 } else
9192 tmp =
9193 xmlHashLookup2(partitions->triage, cur->name,
9194 NULL);
9195 if (tmp == NULL)
9196 tmp =
9197 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9198 NULL);
9199 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009200
Daniel Veillard4c004142003-10-07 11:33:24 +00009201 if (tmp == NULL) {
9202 i = nbgroups;
9203 } else {
9204 i = ((long) tmp) - 1;
9205 if (partitions->flags & IS_NEEDCHECK) {
9206 group = partitions->groups[i];
9207 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9208 i = nbgroups;
9209 }
9210 }
9211 } else {
9212 for (i = 0; i < nbgroups; i++) {
9213 group = partitions->groups[i];
9214 if (group == NULL)
9215 continue;
9216 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9217 break;
9218 }
9219 }
9220 /*
9221 * We break as soon as an element not matched is found
9222 */
9223 if (i >= nbgroups) {
9224 break;
9225 }
9226 if (lasts[i] != NULL) {
9227 lasts[i]->next = cur;
9228 lasts[i] = cur;
9229 } else {
9230 list[i] = cur;
9231 lasts[i] = cur;
9232 }
9233 if (cur->next != NULL)
9234 lastchg = cur->next;
9235 else
9236 lastchg = cur;
9237 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009238 }
9239 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009240 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9241 ret = -1;
9242 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009243 }
9244 lastelem = cur;
9245 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009246 for (i = 0; i < nbgroups; i++) {
9247 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9248 group = partitions->groups[i];
9249 if (lasts[i] != NULL) {
9250 last = lasts[i]->next;
9251 lasts[i]->next = NULL;
9252 }
9253 ctxt->state->seq = list[i];
9254 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9255 if (ret != 0)
9256 break;
9257 if (ctxt->state != NULL) {
9258 cur = ctxt->state->seq;
9259 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9260 xmlRelaxNGFreeValidState(ctxt, oldstate);
9261 oldstate = ctxt->state;
9262 ctxt->state = NULL;
9263 if (cur != NULL) {
9264 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9265 ret = -1;
9266 ctxt->state = oldstate;
9267 goto done;
9268 }
9269 } else if (ctxt->states != NULL) {
9270 int j;
9271 int found = 0;
Daniel Veillard87254c82006-02-19 15:27:17 +00009272 int best = -1;
9273 int lowattr = -1;
9274
9275 /*
9276 * PBM: what happen if there is attributes checks in the interleaves
9277 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00009278
Daniel Veillard4c004142003-10-07 11:33:24 +00009279 for (j = 0; j < ctxt->states->nbState; j++) {
9280 cur = ctxt->states->tabState[j]->seq;
9281 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9282 if (cur == NULL) {
Daniel Veillard87254c82006-02-19 15:27:17 +00009283 if (found == 0) {
9284 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9285 best = j;
9286 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009287 found = 1;
Daniel Veillard87254c82006-02-19 15:27:17 +00009288 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9289 /* try to keep the latest one to mach old heuristic */
9290 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9291 best = j;
9292 }
9293 if (lowattr == 0)
9294 break;
9295 } else if (found == 0) {
9296 if (lowattr == -1) {
9297 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9298 best = j;
9299 } else
9300 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9301 /* try to keep the latest one to mach old heuristic */
9302 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9303 best = j;
9304 }
9305 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009306 }
Daniel Veillard87254c82006-02-19 15:27:17 +00009307 /*
9308 * BIG PBM: here we pick only one restarting point :-(
9309 */
Daniel Veillard4c004142003-10-07 11:33:24 +00009310 if (ctxt->states->nbState > 0) {
9311 xmlRelaxNGFreeValidState(ctxt, oldstate);
Daniel Veillard87254c82006-02-19 15:27:17 +00009312 if (best != -1) {
9313 oldstate = ctxt->states->tabState[best];
9314 ctxt->states->tabState[best] = NULL;
9315 } else {
9316 oldstate =
9317 ctxt->states->tabState[ctxt->states->nbState - 1];
9318 ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
9319 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009320 }
Daniel Veillard87254c82006-02-19 15:27:17 +00009321 for (j = 0; j < ctxt->states->nbState ; j++) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009322 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9323 }
9324 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9325 ctxt->states = NULL;
9326 if (found == 0) {
9327 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9328 ret = -1;
9329 ctxt->state = oldstate;
9330 goto done;
9331 }
9332 } else {
9333 ret = -1;
9334 break;
9335 }
9336 if (lasts[i] != NULL) {
9337 lasts[i]->next = last;
9338 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009339 }
9340 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009341 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009342 ctxt->state = oldstate;
9343 ctxt->state->seq = lastelem;
9344 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009345 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9346 ret = -1;
9347 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009348 }
9349
Daniel Veillard4c004142003-10-07 11:33:24 +00009350 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009351 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009352 /*
9353 * builds the next links chain from the prev one
9354 */
9355 cur = lastchg;
9356 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009357 if ((cur == start) || (cur->prev == NULL))
9358 break;
9359 cur->prev->next = cur;
9360 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009361 }
9362 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009363 if (ctxt->errNr > errNr)
9364 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009365 }
9366
9367 xmlFree(list);
9368 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009369 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009370}
9371
9372/**
9373 * xmlRelaxNGValidateDefinitionList:
9374 * @ctxt: a Relax-NG validation context
9375 * @define: the list of definition to verify
9376 *
9377 * Validate the given node content against the (list) of definitions
9378 *
9379 * Returns 0 if the validation succeeded or an error code.
9380 */
9381static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009382xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9383 xmlRelaxNGDefinePtr defines)
9384{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009385 int ret = 0, res;
9386
9387
Daniel Veillard952379b2003-03-17 15:37:12 +00009388 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009389 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9390 BAD_CAST "NULL definition list");
9391 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009392 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009393 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009394 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9395 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9396 if (res < 0)
9397 ret = -1;
9398 } else {
9399 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9400 return (-1);
9401 }
9402 if (res == -1) /* continues on -2 */
9403 break;
9404 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009405 }
9406
Daniel Veillard4c004142003-10-07 11:33:24 +00009407 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009408}
9409
9410/**
9411 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009412 * @ctxt: a Relax-NG validation context
9413 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009414 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009415 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009416 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009417 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009418 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009419 */
9420static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009421xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9422 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9423{
Daniel Veillard580ced82003-03-21 21:22:48 +00009424 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009425
Daniel Veillardfd573f12003-03-16 17:52:32 +00009426 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009427 if (!xmlStrEqual(elem->name, define->name)) {
9428 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9429 return (0);
9430 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009431 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009432 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009433 if (elem->ns == NULL) {
9434 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9435 return (0);
9436 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9437 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9438 elem->name, define->ns);
9439 return (0);
9440 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009441 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009442 (define->name == NULL)) {
9443 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9444 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009445 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009446 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9447 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009448 }
9449
9450 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009451 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009452
9453 define = define->nameClass;
9454 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009455 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009456
Daniel Veillard4c004142003-10-07 11:33:24 +00009457 if (ctxt != NULL) {
9458 oldflags = ctxt->flags;
9459 ctxt->flags |= FLAGS_IGNORABLE;
9460 }
9461
9462 list = define->content;
9463 while (list != NULL) {
9464 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9465 if (ret == 1) {
9466 if (ctxt != NULL)
9467 ctxt->flags = oldflags;
9468 return (0);
9469 }
9470 if (ret < 0) {
9471 if (ctxt != NULL)
9472 ctxt->flags = oldflags;
9473 return (ret);
9474 }
9475 list = list->next;
9476 }
9477 ret = 1;
9478 if (ctxt != NULL) {
9479 ctxt->flags = oldflags;
9480 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009481 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009482 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009483
Daniel Veillard4c004142003-10-07 11:33:24 +00009484 if (ctxt != NULL) {
9485 oldflags = ctxt->flags;
9486 ctxt->flags |= FLAGS_IGNORABLE;
9487 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009488
Daniel Veillard4c004142003-10-07 11:33:24 +00009489 list = define->nameClass;
9490 while (list != NULL) {
9491 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9492 if (ret == 1) {
9493 if (ctxt != NULL)
9494 ctxt->flags = oldflags;
9495 return (1);
9496 }
9497 if (ret < 0) {
9498 if (ctxt != NULL)
9499 ctxt->flags = oldflags;
9500 return (ret);
9501 }
9502 list = list->next;
9503 }
9504 if (ctxt != NULL) {
9505 if (ret != 0) {
9506 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9507 xmlRelaxNGDumpValidError(ctxt);
9508 } else {
9509 if (ctxt->errNr > 0)
9510 xmlRelaxNGPopErrors(ctxt, 0);
9511 }
9512 }
9513 ret = 0;
9514 if (ctxt != NULL) {
9515 ctxt->flags = oldflags;
9516 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009517 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009518 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009519 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009520 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009521}
9522
9523/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009524 * xmlRelaxNGBestState:
9525 * @ctxt: a Relax-NG validation context
9526 *
9527 * Find the "best" state in the ctxt->states list of states to report
9528 * errors about. I.e. a state with no element left in the child list
9529 * or the one with the less attributes left.
9530 * This is called only if a falidation error was detected
9531 *
9532 * Returns the index of the "best" state or -1 in case of error
9533 */
9534static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009535xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9536{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009537 xmlRelaxNGValidStatePtr state;
9538 int i, tmp;
9539 int best = -1;
9540 int value = 1000000;
9541
9542 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9543 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009544 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009545
Daniel Veillard4c004142003-10-07 11:33:24 +00009546 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009547 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009548 if (state == NULL)
9549 continue;
9550 if (state->seq != NULL) {
9551 if ((best == -1) || (value > 100000)) {
9552 value = 100000;
9553 best = i;
9554 }
9555 } else {
9556 tmp = state->nbAttrLeft;
9557 if ((best == -1) || (value > tmp)) {
9558 value = tmp;
9559 best = i;
9560 }
9561 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009562 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009563 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009564}
9565
9566/**
9567 * xmlRelaxNGLogBestError:
9568 * @ctxt: a Relax-NG validation context
9569 *
9570 * Find the "best" state in the ctxt->states list of states to report
9571 * errors about and log it.
9572 */
9573static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009574xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9575{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009576 int best;
9577
9578 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9579 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009580 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009581
9582 best = xmlRelaxNGBestState(ctxt);
9583 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009584 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009585
Daniel Veillard4c004142003-10-07 11:33:24 +00009586 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009587 }
9588}
9589
9590/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009591 * xmlRelaxNGValidateElementEnd:
9592 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009593 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009594 *
9595 * Validate the end of the element, implements check that
9596 * there is nothing left not consumed in the element content
9597 * or in the attribute list.
9598 *
9599 * Returns 0 if the validation succeeded or an error code.
9600 */
9601static int
William M. Brack272693c2003-11-14 16:20:34 +00009602xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009603{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009604 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009605 xmlRelaxNGValidStatePtr state;
9606
9607 state = ctxt->state;
9608 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009609 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9610 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009611 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009612 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9613 state->node->name, state->seq->name);
9614 }
9615 return (-1);
9616 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009617 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009618 for (i = 0; i < state->nbAttrs; i++) {
9619 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009620 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009621 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9622 state->attrs[i]->name, state->node->name);
9623 }
9624 return (-1 - i);
9625 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009626 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009627 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009628}
9629
9630/**
9631 * xmlRelaxNGValidateState:
9632 * @ctxt: a Relax-NG validation context
9633 * @define: the definition to verify
9634 *
9635 * Validate the current state against the definition
9636 *
9637 * Returns 0 if the validation succeeded or an error code.
9638 */
9639static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009640xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9641 xmlRelaxNGDefinePtr define)
9642{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009643 xmlNodePtr node;
9644 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009645 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009646
9647 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009648 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9649 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009650 }
9651
9652 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009653 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009654 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009655 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009656 }
9657#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009658 for (i = 0; i < ctxt->depth; i++)
9659 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009660 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009661 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009662 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009663 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009664 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009665 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009666 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009667 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009668#endif
9669 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009670 switch (define->type) {
9671 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009672 node = xmlRelaxNGSkipIgnored(ctxt, node);
9673 ret = 0;
9674 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009675 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009676 ret = -1;
9677 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009678 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009679 while ((node != NULL) &&
9680 ((node->type == XML_TEXT_NODE) ||
9681 (node->type == XML_COMMENT_NODE) ||
9682 (node->type == XML_PI_NODE) ||
9683 (node->type == XML_CDATA_SECTION_NODE)))
9684 node = node->next;
9685 ctxt->state->seq = node;
9686 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009687 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009688 errNr = ctxt->errNr;
9689 node = xmlRelaxNGSkipIgnored(ctxt, node);
9690 if (node == NULL) {
9691 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9692 ret = -1;
9693 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9694 xmlRelaxNGDumpValidError(ctxt);
9695 break;
9696 }
9697 if (node->type != XML_ELEMENT_NODE) {
9698 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9699 ret = -1;
9700 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9701 xmlRelaxNGDumpValidError(ctxt);
9702 break;
9703 }
9704 /*
9705 * This node was already validated successfully against
9706 * this definition.
9707 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009708 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009709 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9710 if (ctxt->errNr > errNr)
9711 xmlRelaxNGPopErrors(ctxt, errNr);
9712 if (ctxt->errNr != 0) {
9713 while ((ctxt->err != NULL) &&
9714 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9715 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9716 ||
9717 ((ctxt->err->err ==
9718 XML_RELAXNG_ERR_ELEMEXTRANS)
9719 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9720 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9721 || (ctxt->err->err ==
9722 XML_RELAXNG_ERR_NOTELEM)))
9723 xmlRelaxNGValidErrorPop(ctxt);
9724 }
9725 break;
9726 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009727
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009728 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9729 if (ret <= 0) {
9730 ret = -1;
9731 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9732 xmlRelaxNGDumpValidError(ctxt);
9733 break;
9734 }
9735 ret = 0;
9736 if (ctxt->errNr != 0) {
9737 if (ctxt->errNr > errNr)
9738 xmlRelaxNGPopErrors(ctxt, errNr);
9739 while ((ctxt->err != NULL) &&
9740 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9741 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9742 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9743 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9744 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9745 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9746 xmlRelaxNGValidErrorPop(ctxt);
9747 }
9748 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009749
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009750 oldflags = ctxt->flags;
9751 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9752 ctxt->flags -= FLAGS_MIXED_CONTENT;
9753 }
9754 state = xmlRelaxNGNewValidState(ctxt, node);
9755 if (state == NULL) {
9756 ret = -1;
9757 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9758 xmlRelaxNGDumpValidError(ctxt);
9759 break;
9760 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009761
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009762 oldstate = ctxt->state;
9763 ctxt->state = state;
9764 if (define->attrs != NULL) {
9765 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9766 if (tmp != 0) {
9767 ret = -1;
9768 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9769 }
9770 }
9771 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009772 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9773 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9774 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009775
Daniel Veillard4c004142003-10-07 11:33:24 +00009776 nstate = xmlRelaxNGNewValidState(ctxt, node);
9777 ctxt->state = nstate;
9778 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009779
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009780 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9781 define->contModel,
9782 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009783 nseq = ctxt->state->seq;
9784 ctxt->state = tmpstate;
9785 ctxt->states = tmpstates;
9786 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009787
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009788#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009789 xmlGenericError(xmlGenericErrorContext,
9790 "Validating content of '%s' : %d\n",
9791 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009792#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009793 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009794 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009795
9796 if (ctxt->states != NULL) {
9797 tmp = -1;
9798
Daniel Veillardce192eb2003-04-16 15:58:05 +00009799 for (i = 0; i < ctxt->states->nbState; i++) {
9800 state = ctxt->states->tabState[i];
9801 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009802 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009803
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009804 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009805 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009806 break;
9807 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009808 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009809 if (tmp != 0) {
9810 /*
9811 * validation error, log the message for the "best" one
9812 */
9813 ctxt->flags |= FLAGS_IGNORABLE;
9814 xmlRelaxNGLogBestError(ctxt);
9815 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009816 for (i = 0; i < ctxt->states->nbState; i++) {
9817 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009818 ctxt->states->
9819 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009820 }
9821 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9822 ctxt->flags = oldflags;
9823 ctxt->states = NULL;
9824 if ((ret == 0) && (tmp == -1))
9825 ret = -1;
9826 } else {
9827 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009828 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009829 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009830 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009831 xmlRelaxNGFreeValidState(ctxt, state);
9832 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009833 } else {
9834 if (define->content != NULL) {
9835 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009836 define->
9837 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009838 if (tmp != 0) {
9839 ret = -1;
9840 if (ctxt->state == NULL) {
9841 ctxt->state = oldstate;
9842 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9843 node->name);
9844 ctxt->state = NULL;
9845 } else {
9846 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9847 node->name);
9848 }
9849
9850 }
9851 }
9852 if (ctxt->states != NULL) {
9853 tmp = -1;
9854
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009855 for (i = 0; i < ctxt->states->nbState; i++) {
9856 state = ctxt->states->tabState[i];
9857 ctxt->state = state;
9858
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009859 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009860 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009861 break;
9862 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009863 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009864 if (tmp != 0) {
9865 /*
9866 * validation error, log the message for the "best" one
9867 */
9868 ctxt->flags |= FLAGS_IGNORABLE;
9869 xmlRelaxNGLogBestError(ctxt);
9870 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009871 for (i = 0; i < ctxt->states->nbState; i++) {
9872 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009873 ctxt->states->
9874 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009875 }
9876 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9877 ctxt->flags = oldflags;
9878 ctxt->states = NULL;
9879 if ((ret == 0) && (tmp == -1))
9880 ret = -1;
9881 } else {
9882 state = ctxt->state;
9883 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009884 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009885 xmlRelaxNGFreeValidState(ctxt, state);
9886 }
9887 }
9888 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009889 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009890 }
9891 ctxt->flags = oldflags;
9892 ctxt->state = oldstate;
9893 if (oldstate != NULL)
9894 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9895 if (ret != 0) {
9896 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9897 xmlRelaxNGDumpValidError(ctxt);
9898 ret = 0;
9899 } else {
9900 ret = -2;
9901 }
9902 } else {
9903 if (ctxt->errNr > errNr)
9904 xmlRelaxNGPopErrors(ctxt, errNr);
9905 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009906
9907#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009908 xmlGenericError(xmlGenericErrorContext,
9909 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9910 node->name, ret);
9911 if (oldstate == NULL)
9912 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9913 else if (oldstate->seq == NULL)
9914 xmlGenericError(xmlGenericErrorContext, ": done\n");
9915 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9916 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9917 oldstate->seq->name);
9918 else
9919 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9920 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009921#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009922 break;
9923 case XML_RELAXNG_OPTIONAL:{
9924 errNr = ctxt->errNr;
9925 oldflags = ctxt->flags;
9926 ctxt->flags |= FLAGS_IGNORABLE;
9927 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9928 ret =
9929 xmlRelaxNGValidateDefinitionList(ctxt,
9930 define->content);
9931 if (ret != 0) {
9932 if (ctxt->state != NULL)
9933 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9934 ctxt->state = oldstate;
9935 ctxt->flags = oldflags;
9936 ret = 0;
9937 if (ctxt->errNr > errNr)
9938 xmlRelaxNGPopErrors(ctxt, errNr);
9939 break;
9940 }
9941 if (ctxt->states != NULL) {
9942 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9943 } else {
9944 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9945 if (ctxt->states == NULL) {
9946 xmlRelaxNGFreeValidState(ctxt, oldstate);
9947 ctxt->flags = oldflags;
9948 ret = -1;
9949 if (ctxt->errNr > errNr)
9950 xmlRelaxNGPopErrors(ctxt, errNr);
9951 break;
9952 }
9953 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9954 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9955 ctxt->state = NULL;
9956 }
9957 ctxt->flags = oldflags;
9958 ret = 0;
9959 if (ctxt->errNr > errNr)
9960 xmlRelaxNGPopErrors(ctxt, errNr);
9961 break;
9962 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009963 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009964 errNr = ctxt->errNr;
9965 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9966 if (ret != 0) {
9967 break;
9968 }
9969 if (ctxt->errNr > errNr)
9970 xmlRelaxNGPopErrors(ctxt, errNr);
9971 /* no break on purpose */
9972 case XML_RELAXNG_ZEROORMORE:{
9973 int progress;
9974 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9975 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009976
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009977 errNr = ctxt->errNr;
9978 res = xmlRelaxNGNewStates(ctxt, 1);
9979 if (res == NULL) {
9980 ret = -1;
9981 break;
9982 }
9983 /*
9984 * All the input states are also exit states
9985 */
9986 if (ctxt->state != NULL) {
9987 xmlRelaxNGAddStates(ctxt, res,
9988 xmlRelaxNGCopyValidState(ctxt,
9989 ctxt->
9990 state));
9991 } else {
9992 for (j = 0; j < ctxt->states->nbState; j++) {
9993 xmlRelaxNGAddStates(ctxt, res,
9994 xmlRelaxNGCopyValidState(ctxt,
9995 ctxt->
9996 states->
9997 tabState
9998 [j]));
9999 }
10000 }
10001 oldflags = ctxt->flags;
10002 ctxt->flags |= FLAGS_IGNORABLE;
10003 do {
10004 progress = 0;
10005 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010006
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010007 if (ctxt->states != NULL) {
10008 states = ctxt->states;
10009 for (i = 0; i < states->nbState; i++) {
10010 ctxt->state = states->tabState[i];
10011 ctxt->states = NULL;
10012 ret = xmlRelaxNGValidateDefinitionList(ctxt,
10013 define->
10014 content);
10015 if (ret == 0) {
10016 if (ctxt->state != NULL) {
10017 tmp = xmlRelaxNGAddStates(ctxt, res,
10018 ctxt->state);
10019 ctxt->state = NULL;
10020 if (tmp == 1)
10021 progress = 1;
10022 } else if (ctxt->states != NULL) {
10023 for (j = 0; j < ctxt->states->nbState;
10024 j++) {
10025 tmp =
10026 xmlRelaxNGAddStates(ctxt, res,
10027 ctxt->
10028 states->
10029 tabState
10030 [j]);
10031 if (tmp == 1)
10032 progress = 1;
10033 }
10034 xmlRelaxNGFreeStates(ctxt,
10035 ctxt->states);
10036 ctxt->states = NULL;
10037 }
10038 } else {
10039 if (ctxt->state != NULL) {
10040 xmlRelaxNGFreeValidState(ctxt,
10041 ctxt->state);
10042 ctxt->state = NULL;
10043 }
10044 }
10045 }
10046 } else {
10047 ret = xmlRelaxNGValidateDefinitionList(ctxt,
10048 define->
10049 content);
10050 if (ret != 0) {
10051 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10052 ctxt->state = NULL;
10053 } else {
10054 base = res->nbState;
10055 if (ctxt->state != NULL) {
10056 tmp = xmlRelaxNGAddStates(ctxt, res,
10057 ctxt->state);
10058 ctxt->state = NULL;
10059 if (tmp == 1)
10060 progress = 1;
10061 } else if (ctxt->states != NULL) {
10062 for (j = 0; j < ctxt->states->nbState; j++) {
10063 tmp = xmlRelaxNGAddStates(ctxt, res,
10064 ctxt->
10065 states->
10066 tabState[j]);
10067 if (tmp == 1)
10068 progress = 1;
10069 }
10070 if (states == NULL) {
10071 states = ctxt->states;
10072 } else {
10073 xmlRelaxNGFreeStates(ctxt,
10074 ctxt->states);
10075 }
10076 ctxt->states = NULL;
10077 }
10078 }
10079 }
10080 if (progress) {
10081 /*
10082 * Collect all the new nodes added at that step
10083 * and make them the new node set
10084 */
10085 if (res->nbState - base == 1) {
10086 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10087 res->
10088 tabState
10089 [base]);
10090 } else {
10091 if (states == NULL) {
10092 xmlRelaxNGNewStates(ctxt,
10093 res->nbState - base);
10094 }
10095 states->nbState = 0;
10096 for (i = base; i < res->nbState; i++)
10097 xmlRelaxNGAddStates(ctxt, states,
10098 xmlRelaxNGCopyValidState
10099 (ctxt,
10100 res->tabState[i]));
10101 ctxt->states = states;
10102 }
10103 }
10104 } while (progress == 1);
10105 if (states != NULL) {
10106 xmlRelaxNGFreeStates(ctxt, states);
10107 }
10108 ctxt->states = res;
10109 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010110#if 0
10111 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010112 * errors may have to be propagated back...
10113 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010114 if (ctxt->errNr > errNr)
10115 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010116#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010117 ret = 0;
10118 break;
10119 }
10120 case XML_RELAXNG_CHOICE:{
10121 xmlRelaxNGDefinePtr list = NULL;
10122 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010123
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010124 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010125
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010126 errNr = ctxt->errNr;
Daniel Veillard9186a1f2005-01-15 12:38:10 +000010127 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10128 (node != NULL)) {
10129 /*
10130 * node == NULL can't be optimized since IS_TRIABLE
10131 * doesn't account for choice which may lead to
10132 * only attributes.
10133 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010134 xmlHashTablePtr triage =
10135 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010136
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010137 /*
10138 * Something we can optimize cleanly there is only one
10139 * possble branch out !
10140 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010141 if ((node->type == XML_TEXT_NODE) ||
10142 (node->type == XML_CDATA_SECTION_NODE)) {
10143 list =
10144 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10145 } else if (node->type == XML_ELEMENT_NODE) {
10146 if (node->ns != NULL) {
10147 list = xmlHashLookup2(triage, node->name,
10148 node->ns->href);
10149 if (list == NULL)
10150 list =
10151 xmlHashLookup2(triage, BAD_CAST "#any",
10152 node->ns->href);
10153 } else
10154 list =
10155 xmlHashLookup2(triage, node->name, NULL);
10156 if (list == NULL)
10157 list =
10158 xmlHashLookup2(triage, BAD_CAST "#any",
10159 NULL);
10160 }
10161 if (list == NULL) {
10162 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010163 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010164 break;
10165 }
10166 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10167 if (ret == 0) {
10168 }
10169 break;
10170 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010171
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010172 list = define->content;
10173 oldflags = ctxt->flags;
10174 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010175
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010176 while (list != NULL) {
10177 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10178 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10179 if (ret == 0) {
10180 if (states == NULL) {
10181 states = xmlRelaxNGNewStates(ctxt, 1);
10182 }
10183 if (ctxt->state != NULL) {
10184 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10185 } else if (ctxt->states != NULL) {
10186 for (i = 0; i < ctxt->states->nbState; i++) {
10187 xmlRelaxNGAddStates(ctxt, states,
10188 ctxt->states->
10189 tabState[i]);
10190 }
10191 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10192 ctxt->states = NULL;
10193 }
10194 } else {
10195 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10196 }
10197 ctxt->state = oldstate;
10198 list = list->next;
10199 }
10200 if (states != NULL) {
10201 xmlRelaxNGFreeValidState(ctxt, oldstate);
10202 ctxt->states = states;
10203 ctxt->state = NULL;
10204 ret = 0;
10205 } else {
10206 ctxt->states = NULL;
10207 }
10208 ctxt->flags = oldflags;
10209 if (ret != 0) {
10210 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10211 xmlRelaxNGDumpValidError(ctxt);
10212 }
10213 } else {
10214 if (ctxt->errNr > errNr)
10215 xmlRelaxNGPopErrors(ctxt, errNr);
10216 }
10217 break;
10218 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010219 case XML_RELAXNG_DEF:
10220 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010221 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10222 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010223 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010224 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10225 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010226 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010227 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10228 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010229 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010230 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010231 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010232 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010233 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010234 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10235 break;
10236 case XML_RELAXNG_DATATYPE:{
10237 xmlNodePtr child;
10238 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010239
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010240 child = node;
10241 while (child != NULL) {
10242 if (child->type == XML_ELEMENT_NODE) {
10243 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10244 node->parent->name);
10245 ret = -1;
10246 break;
10247 } else if ((child->type == XML_TEXT_NODE) ||
10248 (child->type == XML_CDATA_SECTION_NODE)) {
10249 content = xmlStrcat(content, child->content);
10250 }
10251 /* TODO: handle entities ... */
10252 child = child->next;
10253 }
10254 if (ret == -1) {
10255 if (content != NULL)
10256 xmlFree(content);
10257 break;
10258 }
10259 if (content == NULL) {
10260 content = xmlStrdup(BAD_CAST "");
10261 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010262 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010263 ret = -1;
10264 break;
10265 }
10266 }
10267 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10268 ctxt->state->seq);
10269 if (ret == -1) {
10270 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10271 } else if (ret == 0) {
10272 ctxt->state->seq = NULL;
10273 }
10274 if (content != NULL)
10275 xmlFree(content);
10276 break;
10277 }
10278 case XML_RELAXNG_VALUE:{
10279 xmlChar *content = NULL;
10280 xmlChar *oldvalue;
10281 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010282
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010283 child = node;
10284 while (child != NULL) {
10285 if (child->type == XML_ELEMENT_NODE) {
10286 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10287 node->parent->name);
10288 ret = -1;
10289 break;
10290 } else if ((child->type == XML_TEXT_NODE) ||
10291 (child->type == XML_CDATA_SECTION_NODE)) {
10292 content = xmlStrcat(content, child->content);
10293 }
10294 /* TODO: handle entities ... */
10295 child = child->next;
10296 }
10297 if (ret == -1) {
10298 if (content != NULL)
10299 xmlFree(content);
10300 break;
10301 }
10302 if (content == NULL) {
10303 content = xmlStrdup(BAD_CAST "");
10304 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010305 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010306 ret = -1;
10307 break;
10308 }
10309 }
10310 oldvalue = ctxt->state->value;
10311 ctxt->state->value = content;
10312 ret = xmlRelaxNGValidateValue(ctxt, define);
10313 ctxt->state->value = oldvalue;
10314 if (ret == -1) {
10315 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10316 } else if (ret == 0) {
10317 ctxt->state->seq = NULL;
10318 }
10319 if (content != NULL)
10320 xmlFree(content);
10321 break;
10322 }
10323 case XML_RELAXNG_LIST:{
10324 xmlChar *content;
10325 xmlNodePtr child;
10326 xmlChar *oldvalue, *oldendvalue;
10327 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010328
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010329 /*
10330 * Make sure it's only text nodes
10331 */
10332
10333 content = NULL;
10334 child = node;
10335 while (child != NULL) {
10336 if (child->type == XML_ELEMENT_NODE) {
10337 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10338 node->parent->name);
10339 ret = -1;
10340 break;
10341 } else if ((child->type == XML_TEXT_NODE) ||
10342 (child->type == XML_CDATA_SECTION_NODE)) {
10343 content = xmlStrcat(content, child->content);
10344 }
10345 /* TODO: handle entities ... */
10346 child = child->next;
10347 }
10348 if (ret == -1) {
10349 if (content != NULL)
10350 xmlFree(content);
10351 break;
10352 }
10353 if (content == NULL) {
10354 content = xmlStrdup(BAD_CAST "");
10355 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010356 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010357 ret = -1;
10358 break;
10359 }
10360 }
10361 len = xmlStrlen(content);
10362 oldvalue = ctxt->state->value;
10363 oldendvalue = ctxt->state->endvalue;
10364 ctxt->state->value = content;
10365 ctxt->state->endvalue = content + len;
10366 ret = xmlRelaxNGValidateValue(ctxt, define);
10367 ctxt->state->value = oldvalue;
10368 ctxt->state->endvalue = oldendvalue;
10369 if (ret == -1) {
10370 VALID_ERR(XML_RELAXNG_ERR_LIST);
10371 } else if ((ret == 0) && (node != NULL)) {
10372 ctxt->state->seq = node->next;
10373 }
10374 if (content != NULL)
10375 xmlFree(content);
10376 break;
10377 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010378 case XML_RELAXNG_EXCEPT:
10379 case XML_RELAXNG_PARAM:
10380 TODO ret = -1;
10381 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010382 }
10383 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010384#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010385 for (i = 0; i < ctxt->depth; i++)
10386 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010387 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010388 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010389 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010390 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010391 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010392 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010393 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010394 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010395#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010396 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010397}
10398
10399/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010400 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010401 * @ctxt: a Relax-NG validation context
10402 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010403 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010404 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010405 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010406 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010407 */
10408static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010409xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10410 xmlRelaxNGDefinePtr define)
10411{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010412 xmlRelaxNGStatesPtr states, res;
10413 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010414
Daniel Veillardfd573f12003-03-16 17:52:32 +000010415 /*
10416 * We should NOT have both ctxt->state and ctxt->states
10417 */
10418 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010419 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10420 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010421 }
10422
10423 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010424 if (ctxt->states != NULL) {
10425 ctxt->state = ctxt->states->tabState[0];
10426 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10427 ctxt->states = NULL;
10428 }
10429 ret = xmlRelaxNGValidateState(ctxt, define);
10430 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10431 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10432 ctxt->state = NULL;
10433 }
10434 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10435 ctxt->state = ctxt->states->tabState[0];
10436 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10437 ctxt->states = NULL;
10438 }
10439 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010440 }
10441
10442 states = ctxt->states;
10443 ctxt->states = NULL;
10444 res = NULL;
10445 j = 0;
10446 oldflags = ctxt->flags;
10447 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010448 for (i = 0; i < states->nbState; i++) {
10449 ctxt->state = states->tabState[i];
10450 ctxt->states = NULL;
10451 ret = xmlRelaxNGValidateState(ctxt, define);
10452 /*
10453 * We should NOT have both ctxt->state and ctxt->states
10454 */
10455 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10456 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10457 ctxt->state = NULL;
10458 }
10459 if (ret == 0) {
10460 if (ctxt->states == NULL) {
10461 if (res != NULL) {
10462 /* add the state to the container */
10463 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10464 ctxt->state = NULL;
10465 } else {
10466 /* add the state directly in states */
10467 states->tabState[j++] = ctxt->state;
10468 ctxt->state = NULL;
10469 }
10470 } else {
10471 if (res == NULL) {
10472 /* make it the new container and copy other results */
10473 res = ctxt->states;
10474 ctxt->states = NULL;
10475 for (k = 0; k < j; k++)
10476 xmlRelaxNGAddStates(ctxt, res,
10477 states->tabState[k]);
10478 } else {
10479 /* add all the new results to res and reff the container */
10480 for (k = 0; k < ctxt->states->nbState; k++)
10481 xmlRelaxNGAddStates(ctxt, res,
10482 ctxt->states->tabState[k]);
10483 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10484 ctxt->states = NULL;
10485 }
10486 }
10487 } else {
10488 if (ctxt->state != NULL) {
10489 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10490 ctxt->state = NULL;
10491 } else if (ctxt->states != NULL) {
10492 for (k = 0; k < ctxt->states->nbState; k++)
10493 xmlRelaxNGFreeValidState(ctxt,
10494 ctxt->states->tabState[k]);
10495 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10496 ctxt->states = NULL;
10497 }
10498 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010499 }
10500 ctxt->flags = oldflags;
10501 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010502 xmlRelaxNGFreeStates(ctxt, states);
10503 ctxt->states = res;
10504 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010505 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010506 states->nbState = j;
10507 ctxt->states = states;
10508 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010509 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010510 ctxt->state = states->tabState[0];
10511 xmlRelaxNGFreeStates(ctxt, states);
10512 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010513 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010514 ret = -1;
10515 xmlRelaxNGFreeStates(ctxt, states);
10516 if (ctxt->states != NULL) {
10517 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10518 ctxt->states = NULL;
10519 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010520 }
10521 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010522 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10523 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010524 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010525 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010526}
10527
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010528/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010529 * xmlRelaxNGValidateDocument:
10530 * @ctxt: a Relax-NG validation context
10531 * @doc: the document
10532 *
10533 * Validate the given document
10534 *
10535 * Returns 0 if the validation succeeded or an error code.
10536 */
10537static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010538xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10539{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010540 int ret;
10541 xmlRelaxNGPtr schema;
10542 xmlRelaxNGGrammarPtr grammar;
10543 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010544 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010545
10546 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010547 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010548
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010549 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010550 schema = ctxt->schema;
10551 grammar = schema->topgrammar;
10552 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010553 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10554 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010555 }
10556 state = xmlRelaxNGNewValidState(ctxt, NULL);
10557 ctxt->state = state;
10558 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010559 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010560 state = ctxt->state;
10561 node = state->seq;
10562 node = xmlRelaxNGSkipIgnored(ctxt, node);
10563 if (node != NULL) {
10564 if (ret != -1) {
10565 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10566 ret = -1;
10567 }
10568 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010569 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010570 int i;
10571 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010572
Daniel Veillard4c004142003-10-07 11:33:24 +000010573 for (i = 0; i < ctxt->states->nbState; i++) {
10574 state = ctxt->states->tabState[i];
10575 node = state->seq;
10576 node = xmlRelaxNGSkipIgnored(ctxt, node);
10577 if (node == NULL)
10578 tmp = 0;
10579 xmlRelaxNGFreeValidState(ctxt, state);
10580 }
10581 if (tmp == -1) {
10582 if (ret != -1) {
10583 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10584 ret = -1;
10585 }
10586 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010587 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010588 if (ctxt->state != NULL) {
10589 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010590 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010591 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010592 if (ret != 0)
10593 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010594#ifdef DEBUG
10595 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010596 ctxt->error(ctxt->userData,
10597 "%d Extra error messages left on stack !\n",
10598 ctxt->errNr);
10599 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010600 }
10601#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010602#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010603 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010604 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010605
Daniel Veillard4c004142003-10-07 11:33:24 +000010606 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10607 vctxt.valid = 1;
10608 vctxt.error = ctxt->error;
10609 vctxt.warning = ctxt->warning;
10610 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010611
Daniel Veillard4c004142003-10-07 11:33:24 +000010612 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10613 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010614 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010615#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010616 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010617 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010618
Daniel Veillard4c004142003-10-07 11:33:24 +000010619 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010620}
10621
Daniel Veillardfd573f12003-03-16 17:52:32 +000010622/************************************************************************
10623 * *
10624 * Validation interfaces *
10625 * *
10626 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010627
Daniel Veillard6eadf632003-01-23 18:29:16 +000010628/**
10629 * xmlRelaxNGNewValidCtxt:
10630 * @schema: a precompiled XML RelaxNGs
10631 *
10632 * Create an XML RelaxNGs validation context based on the given schema
10633 *
10634 * Returns the validation context or NULL in case of error
10635 */
10636xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010637xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10638{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010639 xmlRelaxNGValidCtxtPtr ret;
10640
10641 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10642 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010643 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010644 return (NULL);
10645 }
10646 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10647 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010648 ret->error = xmlGenericError;
10649 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010650 ret->errNr = 0;
10651 ret->errMax = 0;
10652 ret->err = NULL;
10653 ret->errTab = NULL;
Daniel Veillardb30ca312005-09-04 13:50:03 +000010654 if (schema != NULL)
10655 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010656 ret->states = NULL;
10657 ret->freeState = NULL;
10658 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010659 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010660 return (ret);
10661}
10662
10663/**
10664 * xmlRelaxNGFreeValidCtxt:
10665 * @ctxt: the schema validation context
10666 *
10667 * Free the resources associated to the schema validation context
10668 */
10669void
Daniel Veillard4c004142003-10-07 11:33:24 +000010670xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10671{
Daniel Veillard798024a2003-03-19 10:36:09 +000010672 int k;
10673
Daniel Veillard6eadf632003-01-23 18:29:16 +000010674 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010675 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010676 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010677 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010678 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010679 for (k = 0; k < ctxt->freeState->nbState; k++) {
10680 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10681 }
10682 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010683 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010684 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010685 for (k = 0; k < ctxt->freeStatesNr; k++) {
10686 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10687 }
10688 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010689 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010690 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010691 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010692 if (ctxt->elemTab != NULL) {
10693 xmlRegExecCtxtPtr exec;
10694
Daniel Veillard4c004142003-10-07 11:33:24 +000010695 exec = xmlRelaxNGElemPop(ctxt);
10696 while (exec != NULL) {
10697 xmlRegFreeExecCtxt(exec);
10698 exec = xmlRelaxNGElemPop(ctxt);
10699 }
10700 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010701 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010702 xmlFree(ctxt);
10703}
10704
10705/**
10706 * xmlRelaxNGSetValidErrors:
10707 * @ctxt: a Relax-NG validation context
10708 * @err: the error function
10709 * @warn: the warning function
10710 * @ctx: the functions context
10711 *
10712 * Set the error and warning callback informations
10713 */
10714void
10715xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010716 xmlRelaxNGValidityErrorFunc err,
10717 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10718{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010719 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010720 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010721 ctxt->error = err;
10722 ctxt->warning = warn;
10723 ctxt->userData = ctx;
Daniel Veillardb30ca312005-09-04 13:50:03 +000010724 ctxt->serror = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010725}
10726
10727/**
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010728 * xmlRelaxNGSetValidStructuredErrors:
10729 * @ctxt: a Relax-NG validation context
10730 * @serror: the structured error function
10731 * @ctx: the functions context
10732 *
10733 * Set the structured error callback
10734 */
10735void
10736xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardb30ca312005-09-04 13:50:03 +000010737 xmlStructuredErrorFunc serror, void *ctx)
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010738{
10739 if (ctxt == NULL)
10740 return;
Daniel Veillardb30ca312005-09-04 13:50:03 +000010741 ctxt->serror = serror;
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010742 ctxt->error = NULL;
10743 ctxt->warning = NULL;
10744 ctxt->userData = ctx;
10745}
10746
10747/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010748 * xmlRelaxNGGetValidErrors:
10749 * @ctxt: a Relax-NG validation context
10750 * @err: the error function result
10751 * @warn: the warning function result
10752 * @ctx: the functions context result
10753 *
10754 * Get the error and warning callback informations
10755 *
10756 * Returns -1 in case of error and 0 otherwise
10757 */
10758int
10759xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010760 xmlRelaxNGValidityErrorFunc * err,
10761 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10762{
Daniel Veillard409a8142003-07-18 15:16:57 +000010763 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010764 return (-1);
10765 if (err != NULL)
10766 *err = ctxt->error;
10767 if (warn != NULL)
10768 *warn = ctxt->warning;
10769 if (ctx != NULL)
10770 *ctx = ctxt->userData;
10771 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010772}
10773
10774/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010775 * xmlRelaxNGValidateDoc:
10776 * @ctxt: a Relax-NG validation context
10777 * @doc: a parsed document tree
10778 *
10779 * Validate a document tree in memory.
10780 *
10781 * Returns 0 if the document is valid, a positive error code
10782 * number otherwise and -1 in case of internal or API error.
10783 */
10784int
Daniel Veillard4c004142003-10-07 11:33:24 +000010785xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10786{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010787 int ret;
10788
10789 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010790 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010791
10792 ctxt->doc = doc;
10793
10794 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010795 /*
10796 * TODO: build error codes
10797 */
10798 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010799 return (1);
10800 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010801}
10802
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010803#define bottom_relaxng
10804#include "elfgcchack.h"
Daniel Veillard6eadf632003-01-23 18:29:16 +000010805#endif /* LIBXML_SCHEMAS_ENABLED */