blob: b7a0711bd1aa3ba8078705c2bf70f4d3042352f6 [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 Veillardd41f4f42003-01-29 21:07:52 +000011 * - error reporting
Daniel Veillard1ed7f362003-02-03 10:57:45 +000012 * - handle namespace declarations as attributes.
Daniel Veillardf4b4f982003-02-13 11:02:08 +000013 * - add support for DTD compatibility spec
14 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardfd573f12003-03-16 17:52:32 +000015 * - report better mem allocations at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000016 */
17
Daniel Veillard6eadf632003-01-23 18:29:16 +000018#define IN_LIBXML
19#include "libxml.h"
20
21#ifdef LIBXML_SCHEMAS_ENABLED
22
23#include <string.h>
24#include <stdio.h>
25#include <libxml/xmlmemory.h>
26#include <libxml/parser.h>
27#include <libxml/parserInternals.h>
28#include <libxml/hash.h>
29#include <libxml/uri.h>
30
31#include <libxml/relaxng.h>
32
33#include <libxml/xmlschemastypes.h>
34#include <libxml/xmlautomata.h>
35#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000036#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000037
38/*
39 * The Relax-NG namespace
40 */
41static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
42 "http://relaxng.org/ns/structure/1.0";
43
44#define IS_RELAXNG(node, type) \
45 ((node != NULL) && (node->ns != NULL) && \
46 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
47 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
48
49
Daniel Veillard952379b2003-03-17 15:37:12 +000050/* #define DEBUG 1 */
Daniel Veillardc482e262003-02-26 14:48:48 +000051/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard71531f32003-02-05 13:19:53 +000052/* #define DEBUG_CONTENT 1 */
53/* #define DEBUG_TYPE 1 */
54/* #define DEBUG_VALID 1 */
Daniel Veillarde5b110b2003-02-04 14:43:39 +000055/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard416589a2003-02-17 17:25:42 +000056/* #define DEBUG_LIST 1 */
Daniel Veillard5add8682003-03-10 13:13:58 +000057/* #define DEBUG_INCLUDE */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000058/* #define DEBUG_ERROR 1 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000059/* #define DEBUG_COMPILE 1 */
Daniel Veillardf4e55762003-04-15 23:32:22 +000060/* #define DEBUG_PROGRESSIVE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000061
Daniel Veillard5f1946a2003-03-31 16:38:16 +000062#define MAX_ERROR 5
63
Daniel Veillard6eadf632003-01-23 18:29:16 +000064#define TODO \
65 xmlGenericError(xmlGenericErrorContext, \
66 "Unimplemented block at %s:%d\n", \
67 __FILE__, __LINE__);
68
69typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
70typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
71
72typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
73typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
74
Daniel Veillardd41f4f42003-01-29 21:07:52 +000075typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
76typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
77
Daniel Veillarda9d912d2003-02-01 17:43:10 +000078typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
79typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
80
Daniel Veillard6eadf632003-01-23 18:29:16 +000081typedef enum {
82 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
83 XML_RELAXNG_COMBINE_CHOICE, /* choice */
84 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
85} xmlRelaxNGCombine;
86
Daniel Veillard4c5cf702003-02-21 15:40:34 +000087typedef enum {
88 XML_RELAXNG_CONTENT_ERROR = -1,
89 XML_RELAXNG_CONTENT_EMPTY = 0,
90 XML_RELAXNG_CONTENT_SIMPLE,
91 XML_RELAXNG_CONTENT_COMPLEX
92} xmlRelaxNGContentType;
93
Daniel Veillard6eadf632003-01-23 18:29:16 +000094typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
95typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
96
97struct _xmlRelaxNGGrammar {
98 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
99 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
100 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
101 xmlRelaxNGDefinePtr start; /* <start> content */
102 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000103 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000104 xmlHashTablePtr defs; /* define* */
105 xmlHashTablePtr refs; /* references */
106};
107
108
Daniel Veillard6eadf632003-01-23 18:29:16 +0000109typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000110 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000111 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
112 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000113 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114 XML_RELAXNG_TEXT, /* textual content */
115 XML_RELAXNG_ELEMENT, /* an element */
116 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000117 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000118 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
119 XML_RELAXNG_LIST, /* a list of patterns */
120 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
121 XML_RELAXNG_DEF, /* a definition */
122 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000123 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000124 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000125 XML_RELAXNG_OPTIONAL, /* optional patterns */
126 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000127 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
128 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
129 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000130 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000131 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000132} xmlRelaxNGType;
133
Daniel Veillard52b48c72003-04-13 19:53:42 +0000134#define IS_NULLABLE (1 << 0)
135#define IS_NOT_NULLABLE (1 << 1)
136#define IS_INDETERMINIST (1 << 2)
137#define IS_MIXED (1 << 3)
138#define IS_TRIABLE (1 << 4)
139#define IS_PROCESSED (1 << 5)
140#define IS_COMPILABLE (1 << 6)
141#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000142
Daniel Veillard6eadf632003-01-23 18:29:16 +0000143struct _xmlRelaxNGDefine {
144 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000145 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000146 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000147 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000148 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000149 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000150 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000151 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000152 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000153 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000154 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000155 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000156 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000157 short dflags; /* define related flags */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000158 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000159};
160
161/**
162 * _xmlRelaxNG:
163 *
164 * A RelaxNGs definition
165 */
166struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000167 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000168 xmlRelaxNGGrammarPtr topgrammar;
169 xmlDocPtr doc;
170
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000171 int idref; /* requires idref checking */
172
Daniel Veillard6eadf632003-01-23 18:29:16 +0000173 xmlHashTablePtr defs; /* define */
174 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000175 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
176 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000177 int defNr; /* number of defines used */
178 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000179
Daniel Veillard6eadf632003-01-23 18:29:16 +0000180};
181
Daniel Veillard77648bb2003-02-20 15:03:22 +0000182#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
183#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
184#define XML_RELAXNG_IN_LIST (1 << 2)
185#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
186#define XML_RELAXNG_IN_START (1 << 4)
187#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
188#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
189#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000190#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
191#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000192
193struct _xmlRelaxNGParserCtxt {
194 void *userData; /* user specific data block */
195 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
196 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000197 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000198
199 xmlRelaxNGPtr schema; /* The schema in use */
200 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000201 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000202 int flags; /* parser flags */
203 int nbErrors; /* number of errors at parse time */
204 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000205 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000206 xmlRelaxNGDefinePtr def; /* the current define */
207
208 int nbInterleaves;
209 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000210
Daniel Veillardc482e262003-02-26 14:48:48 +0000211 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
212 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000213 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000214 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000215
Daniel Veillard419a7682003-02-03 23:22:49 +0000216 int defNr; /* number of defines used */
217 int defMax; /* number of defines aloocated */
218 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
219
Daniel Veillard6eadf632003-01-23 18:29:16 +0000220 const char *buffer;
221 int size;
222
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000223 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000224 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000225 int docNr; /* Depth of the parsing stack */
226 int docMax; /* Max depth of the parsing stack */
227 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000228
229 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000230 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000231 int incNr; /* Depth of the include parsing stack */
232 int incMax; /* Max depth of the parsing stack */
233 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000234
235 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000236
237 /* used to compile content models */
238 xmlAutomataPtr am; /* the automata */
239 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000240};
241
242#define FLAGS_IGNORABLE 1
243#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000244#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000245
246/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000247 * xmlRelaxNGInterleaveGroup:
248 *
249 * A RelaxNGs partition set associated to lists of definitions
250 */
251typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
252typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
253struct _xmlRelaxNGInterleaveGroup {
254 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
255 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000256 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000257};
258
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000259#define IS_DETERMINIST 1
260#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000261/**
262 * xmlRelaxNGPartitions:
263 *
264 * A RelaxNGs partition associated to an interleave group
265 */
266typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
267typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
268struct _xmlRelaxNGPartition {
269 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000270 xmlHashTablePtr triage; /* hash table used to direct nodes to the
271 right group when possible */
272 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000273 xmlRelaxNGInterleaveGroupPtr *groups;
274};
275
276/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000277 * xmlRelaxNGValidState:
278 *
279 * A RelaxNGs validation state
280 */
281#define MAX_ATTR 20
282typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
283typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
284struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000285 xmlNodePtr node; /* the current node */
286 xmlNodePtr seq; /* the sequence of children left to validate */
287 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000288 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000289 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000290 xmlChar *value; /* the value when operating on string */
291 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000292 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000293};
294
295/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000296 * xmlRelaxNGStates:
297 *
298 * A RelaxNGs container for validation state
299 */
300typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
301typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
302struct _xmlRelaxNGStates {
303 int nbState; /* the number of states */
304 int maxState; /* the size of the array */
305 xmlRelaxNGValidStatePtr *tabState;
306};
307
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000308#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000309/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000310 * xmlRelaxNGValidError:
311 *
312 * A RelaxNGs validation error
313 */
314typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
315typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
316struct _xmlRelaxNGValidError {
317 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000318 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000319 xmlNodePtr node; /* the current node */
320 xmlNodePtr seq; /* the current child */
321 const xmlChar * arg1; /* first arg */
322 const xmlChar * arg2; /* second arg */
323};
324
325/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000326 * xmlRelaxNGValidCtxt:
327 *
328 * A RelaxNGs validation context
329 */
330
331struct _xmlRelaxNGValidCtxt {
332 void *userData; /* user specific data block */
333 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
334 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
335
336 xmlRelaxNGPtr schema; /* The schema in use */
337 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000338 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000339 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000340 int idref; /* requires idref checking */
Daniel Veillarda507fbf2003-03-31 16:09:37 +0000341 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000342
343 /*
344 * Errors accumulated in branches may have to be stacked to be
345 * provided back when it's sure they affect validation.
346 */
347 xmlRelaxNGValidErrorPtr err; /* Last error */
348 int errNr; /* Depth of the error stack */
349 int errMax; /* Max depth of the error stack */
350 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000351
Daniel Veillardfd573f12003-03-16 17:52:32 +0000352 xmlRelaxNGValidStatePtr state; /* the current validation state */
353 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000354
355 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
356 int freeStatesNr;
357 int freeStatesMax;
358 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000359
360 /*
361 * This is used for "progressive" validation
362 */
363 xmlRegExecCtxtPtr elem; /* the current element regexp */
364 int elemNr; /* the number of element validated */
365 int elemMax; /* the max depth of elements */
366 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
367 int pstate; /* progressive state */
368 xmlNodePtr pnode; /* the current node */
369 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000370};
371
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000372/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000373 * xmlRelaxNGInclude:
374 *
375 * Structure associated to a RelaxNGs document element
376 */
377struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000378 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000379 xmlChar *href; /* the normalized href value */
380 xmlDocPtr doc; /* the associated XML document */
381 xmlRelaxNGDefinePtr content;/* the definitions */
382 xmlRelaxNGPtr schema; /* the schema */
383};
384
385/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000386 * xmlRelaxNGDocument:
387 *
388 * Structure associated to a RelaxNGs document element
389 */
390struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000391 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000392 xmlChar *href; /* the normalized href value */
393 xmlDocPtr doc; /* the associated XML document */
394 xmlRelaxNGDefinePtr content;/* the definitions */
395 xmlRelaxNGPtr schema; /* the schema */
396};
397
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000398
Daniel Veillard6eadf632003-01-23 18:29:16 +0000399/************************************************************************
400 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000401 * Preliminary type checking interfaces *
402 * *
403 ************************************************************************/
404/**
405 * xmlRelaxNGTypeHave:
406 * @data: data needed for the library
407 * @type: the type name
408 * @value: the value to check
409 *
410 * Function provided by a type library to check if a type is exported
411 *
412 * Returns 1 if yes, 0 if no and -1 in case of error.
413 */
414typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
415
416/**
417 * xmlRelaxNGTypeCheck:
418 * @data: data needed for the library
419 * @type: the type name
420 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000421 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000422 *
423 * Function provided by a type library to check if a value match a type
424 *
425 * Returns 1 if yes, 0 if no and -1 in case of error.
426 */
427typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000428 const xmlChar *value, void **result,
429 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000430
431/**
432 * xmlRelaxNGFacetCheck:
433 * @data: data needed for the library
434 * @type: the type name
435 * @facet: the facet name
436 * @val: the facet value
437 * @strval: the string value
438 * @value: the value to check
439 *
440 * Function provided by a type library to check a value facet
441 *
442 * Returns 1 if yes, 0 if no and -1 in case of error.
443 */
444typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
445 const xmlChar *facet, const xmlChar *val,
446 const xmlChar *strval, void *value);
447
448/**
449 * xmlRelaxNGTypeFree:
450 * @data: data needed for the library
451 * @result: the value to free
452 *
453 * Function provided by a type library to free a returned result
454 */
455typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000456
457/**
458 * xmlRelaxNGTypeCompare:
459 * @data: data needed for the library
460 * @type: the type name
461 * @value1: the first value
462 * @value2: the second value
463 *
464 * Function provided by a type library to compare two values accordingly
465 * to a type.
466 *
467 * Returns 1 if yes, 0 if no and -1 in case of error.
468 */
469typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
470 const xmlChar *value1,
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000471 xmlNodePtr ctxt1,
472 void *comp1,
473 const xmlChar *value2,
474 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000475typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
476typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
477struct _xmlRelaxNGTypeLibrary {
478 const xmlChar *namespace; /* the datatypeLibrary value */
479 void *data; /* data needed for the library */
480 xmlRelaxNGTypeHave have; /* the export function */
481 xmlRelaxNGTypeCheck check; /* the checking function */
482 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000483 xmlRelaxNGFacetCheck facet; /* the facet check function */
484 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000485};
486
487/************************************************************************
488 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000489 * Allocation functions *
490 * *
491 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000492static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
493static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000494static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000495static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000496static int xmlRelaxNGEqualValidState(
497 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
498 xmlRelaxNGValidStatePtr state1,
499 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000500static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
501 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000502
503/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000504 * xmlRelaxNGFreeDocument:
505 * @docu: a document structure
506 *
507 * Deallocate a RelaxNG document structure.
508 */
509static void
510xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
511{
512 if (docu == NULL)
513 return;
514
515 if (docu->href != NULL)
516 xmlFree(docu->href);
517 if (docu->doc != NULL)
518 xmlFreeDoc(docu->doc);
519 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000520 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000521 xmlFree(docu);
522}
523
524/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000525 * xmlRelaxNGFreeDocumentList:
526 * @docu: a list of document structure
527 *
528 * Deallocate a RelaxNG document structures.
529 */
530static void
531xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
532{
533 xmlRelaxNGDocumentPtr next;
534 while (docu != NULL) {
535 next = docu->next;
536 xmlRelaxNGFreeDocument(docu);
537 docu = next;
538 }
539}
540
541/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000542 * xmlRelaxNGFreeInclude:
543 * @incl: a include structure
544 *
545 * Deallocate a RelaxNG include structure.
546 */
547static void
548xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
549{
550 if (incl == NULL)
551 return;
552
553 if (incl->href != NULL)
554 xmlFree(incl->href);
555 if (incl->doc != NULL)
556 xmlFreeDoc(incl->doc);
557 if (incl->schema != NULL)
558 xmlRelaxNGFree(incl->schema);
559 xmlFree(incl);
560}
561
562/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000563 * xmlRelaxNGFreeIncludeList:
564 * @incl: a include structure list
565 *
566 * Deallocate a RelaxNG include structure.
567 */
568static void
569xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
570{
571 xmlRelaxNGIncludePtr next;
572 while (incl != NULL) {
573 next = incl->next;
574 xmlRelaxNGFreeInclude(incl);
575 incl = next;
576 }
577}
578
579/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000580 * xmlRelaxNGNewRelaxNG:
581 * @ctxt: a Relax-NG validation context (optional)
582 *
583 * Allocate a new RelaxNG structure.
584 *
585 * Returns the newly allocated structure or NULL in case or error
586 */
587static xmlRelaxNGPtr
588xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
589{
590 xmlRelaxNGPtr ret;
591
592 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
593 if (ret == NULL) {
594 if ((ctxt != NULL) && (ctxt->error != NULL))
595 ctxt->error(ctxt->userData, "Out of memory\n");
596 ctxt->nbErrors++;
597 return (NULL);
598 }
599 memset(ret, 0, sizeof(xmlRelaxNG));
600
601 return (ret);
602}
603
604/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000605 * xmlRelaxNGFreeInnerSchema:
606 * @schema: a schema structure
607 *
608 * Deallocate a RelaxNG schema structure.
609 */
610static void
611xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
612{
613 if (schema == NULL)
614 return;
615
616 if (schema->doc != NULL)
617 xmlFreeDoc(schema->doc);
618 if (schema->defTab != NULL) {
619 int i;
620
621 for (i = 0;i < schema->defNr;i++)
622 xmlRelaxNGFreeDefine(schema->defTab[i]);
623 xmlFree(schema->defTab);
624 }
625
626 xmlFree(schema);
627}
628
629/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000630 * xmlRelaxNGFree:
631 * @schema: a schema structure
632 *
633 * Deallocate a RelaxNG structure.
634 */
635void
636xmlRelaxNGFree(xmlRelaxNGPtr schema)
637{
638 if (schema == NULL)
639 return;
640
Daniel Veillard6eadf632003-01-23 18:29:16 +0000641 if (schema->topgrammar != NULL)
642 xmlRelaxNGFreeGrammar(schema->topgrammar);
643 if (schema->doc != NULL)
644 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000645 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000646 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000647 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000648 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000649 if (schema->defTab != NULL) {
650 int i;
651
652 for (i = 0;i < schema->defNr;i++)
653 xmlRelaxNGFreeDefine(schema->defTab[i]);
654 xmlFree(schema->defTab);
655 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000656
657 xmlFree(schema);
658}
659
660/**
661 * xmlRelaxNGNewGrammar:
662 * @ctxt: a Relax-NG validation context (optional)
663 *
664 * Allocate a new RelaxNG grammar.
665 *
666 * Returns the newly allocated structure or NULL in case or error
667 */
668static xmlRelaxNGGrammarPtr
669xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
670{
671 xmlRelaxNGGrammarPtr ret;
672
673 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
674 if (ret == NULL) {
675 if ((ctxt != NULL) && (ctxt->error != NULL))
676 ctxt->error(ctxt->userData, "Out of memory\n");
677 ctxt->nbErrors++;
678 return (NULL);
679 }
680 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
681
682 return (ret);
683}
684
685/**
686 * xmlRelaxNGFreeGrammar:
687 * @grammar: a grammar structure
688 *
689 * Deallocate a RelaxNG grammar structure.
690 */
691static void
692xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
693{
694 if (grammar == NULL)
695 return;
696
Daniel Veillardc482e262003-02-26 14:48:48 +0000697 if (grammar->children != NULL) {
698 xmlRelaxNGFreeGrammar(grammar->children);
699 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000700 if (grammar->next != NULL) {
701 xmlRelaxNGFreeGrammar(grammar->next);
702 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000703 if (grammar->refs != NULL) {
704 xmlHashFree(grammar->refs, NULL);
705 }
706 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000707 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000708 }
709
710 xmlFree(grammar);
711}
712
713/**
714 * xmlRelaxNGNewDefine:
715 * @ctxt: a Relax-NG validation context
716 * @node: the node in the input document.
717 *
718 * Allocate a new RelaxNG define.
719 *
720 * Returns the newly allocated structure or NULL in case or error
721 */
722static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000723xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000724{
725 xmlRelaxNGDefinePtr ret;
726
Daniel Veillard419a7682003-02-03 23:22:49 +0000727 if (ctxt->defMax == 0) {
728 ctxt->defMax = 16;
729 ctxt->defNr = 0;
730 ctxt->defTab = (xmlRelaxNGDefinePtr *)
731 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
732 if (ctxt->defTab == NULL) {
733 if ((ctxt != NULL) && (ctxt->error != NULL))
734 ctxt->error(ctxt->userData, "Out of memory\n");
735 ctxt->nbErrors++;
736 return (NULL);
737 }
738 } else if (ctxt->defMax <= ctxt->defNr) {
739 xmlRelaxNGDefinePtr *tmp;
740 ctxt->defMax *= 2;
741 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
742 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
743 if (tmp == NULL) {
744 if ((ctxt != NULL) && (ctxt->error != NULL))
745 ctxt->error(ctxt->userData, "Out of memory\n");
746 ctxt->nbErrors++;
747 return (NULL);
748 }
749 ctxt->defTab = tmp;
750 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000751 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
752 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000753 if ((ctxt != NULL) && (ctxt->error != NULL))
754 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000755 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000756 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000757 }
758 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000759 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000760 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000761 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000762 return (ret);
763}
764
765/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000766 * xmlRelaxNGFreePartition:
767 * @partitions: a partition set structure
768 *
769 * Deallocate RelaxNG partition set structures.
770 */
771static void
772xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
773 xmlRelaxNGInterleaveGroupPtr group;
774 int j;
775
776 if (partitions != NULL) {
777 if (partitions->groups != NULL) {
778 for (j = 0;j < partitions->nbgroups;j++) {
779 group = partitions->groups[j];
780 if (group != NULL) {
781 if (group->defs != NULL)
782 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000783 if (group->attrs != NULL)
784 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000785 xmlFree(group);
786 }
787 }
788 xmlFree(partitions->groups);
789 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000790 if (partitions->triage != NULL) {
791 xmlHashFree(partitions->triage, NULL);
792 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000793 xmlFree(partitions);
794 }
795}
796/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000797 * xmlRelaxNGFreeDefine:
798 * @define: a define structure
799 *
800 * Deallocate a RelaxNG define structure.
801 */
802static void
803xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
804{
805 if (define == NULL)
806 return;
807
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000808 if ((define->type == XML_RELAXNG_VALUE) &&
809 (define->attrs != NULL)) {
810 xmlRelaxNGTypeLibraryPtr lib;
811
812 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
813 if ((lib != NULL) && (lib->freef != NULL))
814 lib->freef(lib->data, (void *) define->attrs);
815 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000816 if ((define->data != NULL) &&
817 (define->type == XML_RELAXNG_INTERLEAVE))
818 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000819 if ((define->data != NULL) &&
820 (define->type == XML_RELAXNG_CHOICE))
821 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000822 if (define->name != NULL)
823 xmlFree(define->name);
824 if (define->ns != NULL)
825 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000826 if (define->value != NULL)
827 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000828 if (define->contModel != NULL)
829 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000830 xmlFree(define);
831}
832
833/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000834 * xmlRelaxNGNewStates:
835 * @ctxt: a Relax-NG validation context
836 * @size: the default size for the container
837 *
838 * Allocate a new RelaxNG validation state container
839 * TODO: keep a pool in the ctxt
840 *
841 * Returns the newly allocated structure or NULL in case or error
842 */
843static xmlRelaxNGStatesPtr
844xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
845{
846 xmlRelaxNGStatesPtr ret;
847
Daniel Veillard798024a2003-03-19 10:36:09 +0000848 if ((ctxt != NULL) &&
849 (ctxt->freeState != NULL) &&
850 (ctxt->freeStatesNr > 0)) {
851 ctxt->freeStatesNr--;
852 ret = ctxt->freeStates[ctxt->freeStatesNr];
853 ret->nbState = 0;
854 return(ret);
855 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000856 if (size < 16) size = 16;
857
858 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
859 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
860 if (ret == NULL) {
861 if ((ctxt != NULL) && (ctxt->error != NULL))
862 ctxt->error(ctxt->userData, "Out of memory\n");
863 return (NULL);
864 }
865 ret->nbState = 0;
866 ret->maxState = size;
867 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
868 (size) * sizeof(xmlRelaxNGValidStatePtr));
869 if (ret->tabState == NULL) {
870 if ((ctxt != NULL) && (ctxt->error != NULL))
871 ctxt->error(ctxt->userData, "Out of memory\n");
872 xmlFree(ret->tabState);
873 return (NULL);
874 }
875 return(ret);
876}
877
878/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000879 * xmlRelaxNGAddStateUniq:
880 * @ctxt: a Relax-NG validation context
881 * @states: the states container
882 * @state: the validation state
883 *
884 * Add a RelaxNG validation state to the container without checking
885 * for unicity.
886 *
887 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
888 */
889static int
890xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
891 xmlRelaxNGStatesPtr states,
892 xmlRelaxNGValidStatePtr state)
893{
894 if (state == NULL) {
895 return(-1);
896 }
897 if (states->nbState >= states->maxState) {
898 xmlRelaxNGValidStatePtr *tmp;
899 int size;
900
901 size = states->maxState * 2;
902 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
903 (size) * sizeof(xmlRelaxNGValidStatePtr));
904 if (tmp == NULL) {
905 if ((ctxt != NULL) && (ctxt->error != NULL))
906 ctxt->error(ctxt->userData, "Out of memory\n");
907 return(-1);
908 }
909 states->tabState = tmp;
910 states->maxState = size;
911 }
912 states->tabState[states->nbState++] = state;
913 return(1);
914}
915
916/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000917 * xmlRelaxNGAddState:
918 * @ctxt: a Relax-NG validation context
919 * @states: the states container
920 * @state: the validation state
921 *
922 * Add a RelaxNG validation state to the container
923 *
924 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
925 */
926static int
927xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
928 xmlRelaxNGValidStatePtr state)
929{
930 int i;
931
932 if (state == NULL) {
933 return(-1);
934 }
935 if (states->nbState >= states->maxState) {
936 xmlRelaxNGValidStatePtr *tmp;
937 int size;
938
939 size = states->maxState * 2;
940 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
941 (size) * sizeof(xmlRelaxNGValidStatePtr));
942 if (tmp == NULL) {
943 if ((ctxt != NULL) && (ctxt->error != NULL))
944 ctxt->error(ctxt->userData, "Out of memory\n");
945 return(-1);
946 }
947 states->tabState = tmp;
948 states->maxState = size;
949 }
950 for (i = 0;i < states->nbState;i++) {
951 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000952 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000953 return(0);
954 }
955 }
956 states->tabState[states->nbState++] = state;
957 return(1);
958}
959
960/**
961 * xmlRelaxNGFreeStates:
962 * @ctxt: a Relax-NG validation context
963 * @states: teh container
964 *
965 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000966 */
967static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000968xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000969 xmlRelaxNGStatesPtr states)
970{
Daniel Veillard798024a2003-03-19 10:36:09 +0000971 if (states == NULL)
972 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000973 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
974 ctxt->freeStatesMax = 40;
975 ctxt->freeStatesNr = 0;
976 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
977 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
978 if (ctxt->freeStates == NULL) {
979 if ((ctxt != NULL) && (ctxt->error != NULL))
980 ctxt->error(ctxt->userData, "Out of memory\n");
981 }
982 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
983 xmlRelaxNGStatesPtr *tmp;
984
985 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
986 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
987 if (tmp == NULL) {
988 if ((ctxt != NULL) && (ctxt->error != NULL))
989 ctxt->error(ctxt->userData, "Out of memory\n");
990 xmlFree(states->tabState);
991 xmlFree(states);
992 return;
993 }
994 ctxt->freeStates = tmp;
995 ctxt->freeStatesMax *= 2;
996 }
997 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000998 xmlFree(states->tabState);
999 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001000 } else {
1001 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001002 }
1003}
1004
1005/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001006 * xmlRelaxNGNewValidState:
1007 * @ctxt: a Relax-NG validation context
1008 * @node: the current node or NULL for the document
1009 *
1010 * Allocate a new RelaxNG validation state
1011 *
1012 * Returns the newly allocated structure or NULL in case or error
1013 */
1014static xmlRelaxNGValidStatePtr
1015xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1016{
1017 xmlRelaxNGValidStatePtr ret;
1018 xmlAttrPtr attr;
1019 xmlAttrPtr attrs[MAX_ATTR];
1020 int nbAttrs = 0;
1021 xmlNodePtr root = NULL;
1022
1023 if (node == NULL) {
1024 root = xmlDocGetRootElement(ctxt->doc);
1025 if (root == NULL)
1026 return(NULL);
1027 } else {
1028 attr = node->properties;
1029 while (attr != NULL) {
1030 if (nbAttrs < MAX_ATTR)
1031 attrs[nbAttrs++] = attr;
1032 else
1033 nbAttrs++;
1034 attr = attr->next;
1035 }
1036 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001037 if ((ctxt->freeState != NULL) &&
1038 (ctxt->freeState->nbState > 0)) {
1039 ctxt->freeState->nbState--;
1040 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1041 } else {
1042 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1043 if (ret == NULL) {
1044 if ((ctxt != NULL) && (ctxt->error != NULL))
1045 ctxt->error(ctxt->userData, "Out of memory\n");
1046 return (NULL);
1047 }
1048 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001049 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001050 ret->value = NULL;
1051 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001052 if (node == NULL) {
1053 ret->node = (xmlNodePtr) ctxt->doc;
1054 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001055 } else {
1056 ret->node = node;
1057 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001058 }
1059 ret->nbAttrs = 0;
1060 if (nbAttrs > 0) {
1061 if (ret->attrs == NULL) {
1062 if (nbAttrs < 4) ret->maxAttrs = 4;
1063 else ret->maxAttrs = nbAttrs;
1064 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1065 sizeof(xmlAttrPtr));
1066 if (ret->attrs == NULL) {
1067 if ((ctxt != NULL) && (ctxt->error != NULL))
1068 ctxt->error(ctxt->userData, "Out of memory\n");
1069 return (ret);
1070 }
1071 } else if (ret->maxAttrs < nbAttrs) {
1072 xmlAttrPtr *tmp;
1073
1074 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1075 sizeof(xmlAttrPtr));
1076 if (tmp == NULL) {
1077 if ((ctxt != NULL) && (ctxt->error != NULL))
1078 ctxt->error(ctxt->userData, "Out of memory\n");
1079 return (ret);
1080 }
1081 ret->attrs = tmp;
1082 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001083 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001084 if (nbAttrs < MAX_ATTR) {
1085 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1086 } else {
1087 attr = node->properties;
1088 nbAttrs = 0;
1089 while (attr != NULL) {
1090 ret->attrs[nbAttrs++] = attr;
1091 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001092 }
1093 }
1094 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001095 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001096 return (ret);
1097}
1098
1099/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001100 * xmlRelaxNGCopyValidState:
1101 * @ctxt: a Relax-NG validation context
1102 * @state: a validation state
1103 *
1104 * Copy the validation state
1105 *
1106 * Returns the newly allocated structure or NULL in case or error
1107 */
1108static xmlRelaxNGValidStatePtr
1109xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1110 xmlRelaxNGValidStatePtr state)
1111{
1112 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001113 unsigned int maxAttrs;
1114 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001115
1116 if (state == NULL)
1117 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001118 if ((ctxt->freeState != NULL) &&
1119 (ctxt->freeState->nbState > 0)) {
1120 ctxt->freeState->nbState--;
1121 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1122 } else {
1123 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1124 if (ret == NULL) {
1125 if ((ctxt != NULL) && (ctxt->error != NULL))
1126 ctxt->error(ctxt->userData, "Out of memory\n");
1127 return (NULL);
1128 }
1129 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001130 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001131 attrs = ret->attrs;
1132 maxAttrs = ret->maxAttrs;
1133 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1134 ret->attrs = attrs;
1135 ret->maxAttrs = maxAttrs;
1136 if (state->nbAttrs > 0) {
1137 if (ret->attrs == NULL) {
1138 ret->maxAttrs = state->maxAttrs;
1139 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1140 sizeof(xmlAttrPtr));
1141 if (ret->attrs == NULL) {
1142 if ((ctxt != NULL) && (ctxt->error != NULL))
1143 ctxt->error(ctxt->userData, "Out of memory\n");
1144 ret->nbAttrs = 0;
1145 return (ret);
1146 }
1147 } else if (ret->maxAttrs < state->nbAttrs) {
1148 xmlAttrPtr *tmp;
1149
1150 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1151 sizeof(xmlAttrPtr));
1152 if (tmp == NULL) {
1153 if ((ctxt != NULL) && (ctxt->error != NULL))
1154 ctxt->error(ctxt->userData, "Out of memory\n");
1155 ret->nbAttrs = 0;
1156 return (ret);
1157 }
1158 ret->maxAttrs = state->maxAttrs;
1159 }
1160 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1161 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001162 return(ret);
1163}
1164
1165/**
1166 * xmlRelaxNGEqualValidState:
1167 * @ctxt: a Relax-NG validation context
1168 * @state1: a validation state
1169 * @state2: a validation state
1170 *
1171 * Compare the validation states for equality
1172 *
1173 * Returns 1 if equald, 0 otherwise
1174 */
1175static int
1176xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1177 xmlRelaxNGValidStatePtr state1,
1178 xmlRelaxNGValidStatePtr state2)
1179{
1180 int i;
1181
1182 if ((state1 == NULL) || (state2 == NULL))
1183 return(0);
1184 if (state1 == state2)
1185 return(1);
1186 if (state1->node != state2->node)
1187 return(0);
1188 if (state1->seq != state2->seq)
1189 return(0);
1190 if (state1->nbAttrLeft != state2->nbAttrLeft)
1191 return(0);
1192 if (state1->nbAttrs != state2->nbAttrs)
1193 return(0);
1194 if (state1->endvalue != state2->endvalue)
1195 return(0);
1196 if ((state1->value != state2->value) &&
1197 (!xmlStrEqual(state1->value, state2->value)))
1198 return(0);
1199 for (i = 0;i < state1->nbAttrs;i++) {
1200 if (state1->attrs[i] != state2->attrs[i])
1201 return(0);
1202 }
1203 return(1);
1204}
1205
1206/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001207 * xmlRelaxNGFreeValidState:
1208 * @state: a validation state structure
1209 *
1210 * Deallocate a RelaxNG validation state structure.
1211 */
1212static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001213xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1214 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001215{
1216 if (state == NULL)
1217 return;
1218
Daniel Veillard798024a2003-03-19 10:36:09 +00001219 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1220 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1221 }
1222 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1223 if (state->attrs != NULL)
1224 xmlFree(state->attrs);
1225 xmlFree(state);
1226 } else {
1227 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1228 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001229}
1230
1231/************************************************************************
1232 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001233 * Document functions *
1234 * *
1235 ************************************************************************/
1236static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1237 xmlDocPtr doc);
1238
1239/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001240 * xmlRelaxNGIncludePush:
1241 * @ctxt: the parser context
1242 * @value: the element doc
1243 *
1244 * Pushes a new include on top of the include stack
1245 *
1246 * Returns 0 in case of error, the index in the stack otherwise
1247 */
1248static int
1249xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1250 xmlRelaxNGIncludePtr value)
1251{
1252 if (ctxt->incTab == NULL) {
1253 ctxt->incMax = 4;
1254 ctxt->incNr = 0;
1255 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1256 ctxt->incMax * sizeof(ctxt->incTab[0]));
1257 if (ctxt->incTab == NULL) {
1258 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1259 return (0);
1260 }
1261 }
1262 if (ctxt->incNr >= ctxt->incMax) {
1263 ctxt->incMax *= 2;
1264 ctxt->incTab =
1265 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1266 ctxt->incMax *
1267 sizeof(ctxt->incTab[0]));
1268 if (ctxt->incTab == NULL) {
1269 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1270 return (0);
1271 }
1272 }
1273 ctxt->incTab[ctxt->incNr] = value;
1274 ctxt->inc = value;
1275 return (ctxt->incNr++);
1276}
1277
1278/**
1279 * xmlRelaxNGIncludePop:
1280 * @ctxt: the parser context
1281 *
1282 * Pops the top include from the include stack
1283 *
1284 * Returns the include just removed
1285 */
1286static xmlRelaxNGIncludePtr
1287xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1288{
1289 xmlRelaxNGIncludePtr ret;
1290
1291 if (ctxt->incNr <= 0)
1292 return (0);
1293 ctxt->incNr--;
1294 if (ctxt->incNr > 0)
1295 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1296 else
1297 ctxt->inc = NULL;
1298 ret = ctxt->incTab[ctxt->incNr];
1299 ctxt->incTab[ctxt->incNr] = 0;
1300 return (ret);
1301}
1302
1303/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001304 * xmlRelaxNGRemoveRedefine:
1305 * @ctxt: the parser context
1306 * @URL: the normalized URL
1307 * @target: the included target
1308 * @name: the define name to eliminate
1309 *
1310 * Applies the elimination algorithm of 4.7
1311 *
1312 * Returns 0 in case of error, 1 in case of success.
1313 */
1314static int
1315xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1316 const xmlChar *URL ATTRIBUTE_UNUSED,
1317 xmlNodePtr target, const xmlChar *name) {
1318 int found = 0;
1319 xmlNodePtr tmp, tmp2;
1320 xmlChar *name2;
1321
1322#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001323 if (name == NULL)
1324 xmlGenericError(xmlGenericErrorContext,
1325 "Elimination of <include> start from %s\n", URL);
1326 else
1327 xmlGenericError(xmlGenericErrorContext,
1328 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001329#endif
1330 tmp = target;
1331 while (tmp != NULL) {
1332 tmp2 = tmp->next;
1333 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1334 found = 1;
1335 xmlUnlinkNode(tmp);
1336 xmlFreeNode(tmp);
1337 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1338 name2 = xmlGetProp(tmp, BAD_CAST "name");
1339 xmlRelaxNGNormExtSpace(name2);
1340 if (name2 != NULL) {
1341 if (xmlStrEqual(name, name2)) {
1342 found = 1;
1343 xmlUnlinkNode(tmp);
1344 xmlFreeNode(tmp);
1345 }
1346 xmlFree(name2);
1347 }
1348 } else if (IS_RELAXNG(tmp, "include")) {
1349 xmlChar *href = NULL;
1350 xmlRelaxNGDocumentPtr inc = tmp->_private;
1351
1352 if ((inc != NULL) && (inc->doc != NULL) &&
1353 (inc->doc->children != NULL)) {
1354
1355 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1356#ifdef DEBUG_INCLUDE
1357 href = xmlGetProp(tmp, BAD_CAST "href");
1358#endif
1359 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1360 inc->doc->children->children, name) == 1) {
1361 found = 1;
1362 }
1363 if (href != NULL)
1364 xmlFree(href);
1365 }
1366 }
1367 }
1368 tmp = tmp2;
1369 }
1370 return(found);
1371}
1372
1373/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001374 * xmlRelaxNGLoadInclude:
1375 * @ctxt: the parser context
1376 * @URL: the normalized URL
1377 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001378 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001379 *
1380 * First lookup if the document is already loaded into the parser context,
1381 * check against recursion. If not found the resource is loaded and
1382 * the content is preprocessed before being returned back to the caller.
1383 *
1384 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1385 */
1386static xmlRelaxNGIncludePtr
1387xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001388 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001389 xmlRelaxNGIncludePtr ret = NULL;
1390 xmlDocPtr doc;
1391 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001392 xmlNodePtr root, cur;
1393
1394#ifdef DEBUG_INCLUDE
1395 xmlGenericError(xmlGenericErrorContext,
1396 "xmlRelaxNGLoadInclude(%s)\n", URL);
1397#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001398
1399 /*
1400 * check against recursion in the stack
1401 */
1402 for (i = 0;i < ctxt->incNr;i++) {
1403 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1404 if (ctxt->error != NULL)
1405 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001406 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001407 URL);
1408 ctxt->nbErrors++;
1409 return(NULL);
1410 }
1411 }
1412
1413 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001414 * load the document
1415 */
1416 doc = xmlParseFile((const char *) URL);
1417 if (doc == NULL) {
1418 if (ctxt->error != NULL)
1419 ctxt->error(ctxt->userData,
1420 "xmlRelaxNG: could not load %s\n", URL);
1421 ctxt->nbErrors++;
1422 return (NULL);
1423 }
1424
Daniel Veillard5add8682003-03-10 13:13:58 +00001425#ifdef DEBUG_INCLUDE
1426 xmlGenericError(xmlGenericErrorContext,
1427 "Parsed %s Okay\n", URL);
1428#endif
1429
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001430 /*
1431 * Allocate the document structures and register it first.
1432 */
1433 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1434 if (ret == NULL) {
1435 if (ctxt->error != NULL)
1436 ctxt->error(ctxt->userData,
1437 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1438 ctxt->nbErrors++;
1439 xmlFreeDoc(doc);
1440 return (NULL);
1441 }
1442 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1443 ret->doc = doc;
1444 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001445 ret->next = ctxt->includes;
1446 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001447
1448 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001449 * transmit the ns if needed
1450 */
1451 if (ns != NULL) {
1452 root = xmlDocGetRootElement(doc);
1453 if (root != NULL) {
1454 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1455 xmlSetProp(root, BAD_CAST"ns", ns);
1456 }
1457 }
1458 }
1459
1460 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001461 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001462 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001463 xmlRelaxNGIncludePush(ctxt, ret);
1464
1465 /*
1466 * Some preprocessing of the document content, this include recursing
1467 * in the include stack.
1468 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001469#ifdef DEBUG_INCLUDE
1470 xmlGenericError(xmlGenericErrorContext,
1471 "cleanup of %s\n", URL);
1472#endif
1473
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001474 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1475 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001476 ctxt->inc = NULL;
1477 return(NULL);
1478 }
1479
1480 /*
1481 * Pop up the include from the stack
1482 */
1483 xmlRelaxNGIncludePop(ctxt);
1484
Daniel Veillard5add8682003-03-10 13:13:58 +00001485#ifdef DEBUG_INCLUDE
1486 xmlGenericError(xmlGenericErrorContext,
1487 "Checking of %s\n", URL);
1488#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001489 /*
1490 * Check that the top element is a grammar
1491 */
1492 root = xmlDocGetRootElement(doc);
1493 if (root == NULL) {
1494 if (ctxt->error != NULL)
1495 ctxt->error(ctxt->userData,
1496 "xmlRelaxNG: included document is empty %s\n", URL);
1497 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001498 return (NULL);
1499 }
1500 if (!IS_RELAXNG(root, "grammar")) {
1501 if (ctxt->error != NULL)
1502 ctxt->error(ctxt->userData,
1503 "xmlRelaxNG: included document %s root is not a grammar\n",
1504 URL);
1505 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001506 return (NULL);
1507 }
1508
1509 /*
1510 * Elimination of redefined rules in the include.
1511 */
1512 cur = node->children;
1513 while (cur != NULL) {
1514 if (IS_RELAXNG(cur, "start")) {
1515 int found = 0;
1516
Daniel Veillard5add8682003-03-10 13:13:58 +00001517 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001518 if (!found) {
1519 if (ctxt->error != NULL)
1520 ctxt->error(ctxt->userData,
1521 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1522 URL);
1523 ctxt->nbErrors++;
1524 }
1525 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001526 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001527
1528 name = xmlGetProp(cur, BAD_CAST "name");
1529 if (name == NULL) {
1530 if (ctxt->error != NULL)
1531 ctxt->error(ctxt->userData,
1532 "xmlRelaxNG: include %s has define without name\n",
1533 URL);
1534 ctxt->nbErrors++;
1535 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001536 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001537
Daniel Veillardd2298792003-02-14 16:54:11 +00001538 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001539 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1540 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001541 if (!found) {
1542 if (ctxt->error != NULL)
1543 ctxt->error(ctxt->userData,
1544 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1545 URL, name);
1546 ctxt->nbErrors++;
1547 }
1548 xmlFree(name);
1549 }
1550 }
1551 cur = cur->next;
1552 }
1553
1554
1555 return(ret);
1556}
1557
1558/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001559 * xmlRelaxNGValidErrorPush:
1560 * @ctxt: the validation context
1561 * @err: the error code
1562 * @arg1: the first string argument
1563 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001564 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001565 *
1566 * Pushes a new error on top of the error stack
1567 *
1568 * Returns 0 in case of error, the index in the stack otherwise
1569 */
1570static int
1571xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001572 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001573{
1574 xmlRelaxNGValidErrorPtr cur;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001575#ifdef DEBUG_ERROR
1576 xmlGenericError(xmlGenericErrorContext,
1577 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1578#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001579 if (ctxt->errTab == NULL) {
1580 ctxt->errMax = 8;
1581 ctxt->errNr = 0;
1582 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1583 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1584 if (ctxt->errTab == NULL) {
1585 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1586 return (0);
1587 }
Daniel Veillard20863822003-03-22 17:51:47 +00001588 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001589 }
1590 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001591 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001592 ctxt->errTab =
1593 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001594 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001595 if (ctxt->errTab == NULL) {
1596 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1597 return (0);
1598 }
Daniel Veillard20863822003-03-22 17:51:47 +00001599 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001600 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001601 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001602 (ctxt->err->node == ctxt->state->node) &&
1603 (ctxt->err->err == err))
1604 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001605 cur = &ctxt->errTab[ctxt->errNr];
1606 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001607 if (dup) {
1608 cur->arg1 = xmlStrdup(arg1);
1609 cur->arg2 = xmlStrdup(arg2);
1610 cur->flags = ERROR_IS_DUP;
1611 } else {
1612 cur->arg1 = arg1;
1613 cur->arg2 = arg2;
1614 cur->flags = 0;
1615 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001616 if (ctxt->state != NULL) {
1617 cur->node = ctxt->state->node;
1618 cur->seq = ctxt->state->seq;
1619 } else {
1620 cur->node = NULL;
1621 cur->seq = NULL;
1622 }
1623 ctxt->err = cur;
1624 return (ctxt->errNr++);
1625}
1626
1627/**
1628 * xmlRelaxNGValidErrorPop:
1629 * @ctxt: the validation context
1630 *
1631 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001632 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001633static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001634xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1635{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001636 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001637
Daniel Veillard580ced82003-03-21 21:22:48 +00001638 if (ctxt->errNr <= 0) {
1639 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001640 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001641 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001642 ctxt->errNr--;
1643 if (ctxt->errNr > 0)
1644 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1645 else
1646 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001647 cur = &ctxt->errTab[ctxt->errNr];
1648 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001649 if (cur->arg1 != NULL)
1650 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001651 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001652 if (cur->arg2 != NULL)
1653 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001654 cur->arg2 = NULL;
1655 cur->flags = 0;
1656 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001657}
1658
Daniel Veillard42f12e92003-03-07 18:32:59 +00001659/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001660 * xmlRelaxNGDocumentPush:
1661 * @ctxt: the parser context
1662 * @value: the element doc
1663 *
1664 * Pushes a new doc on top of the doc stack
1665 *
1666 * Returns 0 in case of error, the index in the stack otherwise
1667 */
1668static int
1669xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1670 xmlRelaxNGDocumentPtr value)
1671{
1672 if (ctxt->docTab == NULL) {
1673 ctxt->docMax = 4;
1674 ctxt->docNr = 0;
1675 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1676 ctxt->docMax * sizeof(ctxt->docTab[0]));
1677 if (ctxt->docTab == NULL) {
1678 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1679 return (0);
1680 }
1681 }
1682 if (ctxt->docNr >= ctxt->docMax) {
1683 ctxt->docMax *= 2;
1684 ctxt->docTab =
1685 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1686 ctxt->docMax *
1687 sizeof(ctxt->docTab[0]));
1688 if (ctxt->docTab == NULL) {
1689 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1690 return (0);
1691 }
1692 }
1693 ctxt->docTab[ctxt->docNr] = value;
1694 ctxt->doc = value;
1695 return (ctxt->docNr++);
1696}
1697
1698/**
1699 * xmlRelaxNGDocumentPop:
1700 * @ctxt: the parser context
1701 *
1702 * Pops the top doc from the doc stack
1703 *
1704 * Returns the doc just removed
1705 */
1706static xmlRelaxNGDocumentPtr
1707xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1708{
1709 xmlRelaxNGDocumentPtr ret;
1710
1711 if (ctxt->docNr <= 0)
1712 return (0);
1713 ctxt->docNr--;
1714 if (ctxt->docNr > 0)
1715 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1716 else
1717 ctxt->doc = NULL;
1718 ret = ctxt->docTab[ctxt->docNr];
1719 ctxt->docTab[ctxt->docNr] = 0;
1720 return (ret);
1721}
1722
1723/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001724 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001725 * @ctxt: the parser context
1726 * @URL: the normalized URL
1727 * @ns: the inherited ns if any
1728 *
1729 * First lookup if the document is already loaded into the parser context,
1730 * check against recursion. If not found the resource is loaded and
1731 * the content is preprocessed before being returned back to the caller.
1732 *
1733 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1734 */
1735static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001736xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001737 const xmlChar *ns) {
1738 xmlRelaxNGDocumentPtr ret = NULL;
1739 xmlDocPtr doc;
1740 xmlNodePtr root;
1741 int i;
1742
1743 /*
1744 * check against recursion in the stack
1745 */
1746 for (i = 0;i < ctxt->docNr;i++) {
1747 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1748 if (ctxt->error != NULL)
1749 ctxt->error(ctxt->userData,
1750 "Detected an externalRef recursion for %s\n",
1751 URL);
1752 ctxt->nbErrors++;
1753 return(NULL);
1754 }
1755 }
1756
1757 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001758 * load the document
1759 */
1760 doc = xmlParseFile((const char *) URL);
1761 if (doc == NULL) {
1762 if (ctxt->error != NULL)
1763 ctxt->error(ctxt->userData,
1764 "xmlRelaxNG: could not load %s\n", URL);
1765 ctxt->nbErrors++;
1766 return (NULL);
1767 }
1768
1769 /*
1770 * Allocate the document structures and register it first.
1771 */
1772 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1773 if (ret == NULL) {
1774 if (ctxt->error != NULL)
1775 ctxt->error(ctxt->userData,
1776 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1777 ctxt->nbErrors++;
1778 xmlFreeDoc(doc);
1779 return (NULL);
1780 }
1781 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1782 ret->doc = doc;
1783 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001784 ret->next = ctxt->documents;
1785 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001786
1787 /*
1788 * transmit the ns if needed
1789 */
1790 if (ns != NULL) {
1791 root = xmlDocGetRootElement(doc);
1792 if (root != NULL) {
1793 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1794 xmlSetProp(root, BAD_CAST"ns", ns);
1795 }
1796 }
1797 }
1798
1799 /*
1800 * push it on the stack and register it in the hash table
1801 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001802 xmlRelaxNGDocumentPush(ctxt, ret);
1803
1804 /*
1805 * Some preprocessing of the document content
1806 */
1807 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1808 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001809 ctxt->doc = NULL;
1810 return(NULL);
1811 }
1812
1813 xmlRelaxNGDocumentPop(ctxt);
1814
1815 return(ret);
1816}
1817
1818/************************************************************************
1819 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001820 * Error functions *
1821 * *
1822 ************************************************************************/
1823
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001824#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1825#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1826#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1827#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1828#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001829
Daniel Veillard231d7912003-02-09 14:22:17 +00001830static const char *
1831xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1832 if (def == NULL)
1833 return("none");
1834 switch(def->type) {
1835 case XML_RELAXNG_EMPTY: return("empty");
1836 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1837 case XML_RELAXNG_EXCEPT: return("except");
1838 case XML_RELAXNG_TEXT: return("text");
1839 case XML_RELAXNG_ELEMENT: return("element");
1840 case XML_RELAXNG_DATATYPE: return("datatype");
1841 case XML_RELAXNG_VALUE: return("value");
1842 case XML_RELAXNG_LIST: return("list");
1843 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1844 case XML_RELAXNG_DEF: return("def");
1845 case XML_RELAXNG_REF: return("ref");
1846 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1847 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001848 case XML_RELAXNG_OPTIONAL: return("optional");
1849 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001850 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1851 case XML_RELAXNG_CHOICE: return("choice");
1852 case XML_RELAXNG_GROUP: return("group");
1853 case XML_RELAXNG_INTERLEAVE: return("interleave");
1854 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001855 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001856 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001857 }
1858 return("unknown");
1859}
Daniel Veillardd2298792003-02-14 16:54:11 +00001860
Daniel Veillard6eadf632003-01-23 18:29:16 +00001861/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001862 * xmlRelaxNGGetErrorString:
1863 * @err: the error code
1864 * @arg1: the first string argument
1865 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001866 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001867 * computes a formatted error string for the given error code and args
1868 *
1869 * Returns the error string, it must be deallocated by the caller
1870 */
1871static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001872xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1873 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001874 char msg[1000];
1875
1876 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001877 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001878 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001879 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001880
1881 msg[0] = 0;
1882 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001883 case XML_RELAXNG_OK:
1884 return(NULL);
1885 case XML_RELAXNG_ERR_MEMORY:
1886 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001887 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001888 snprintf(msg, 1000, "failed to validate type %s", arg1);
1889 break;
1890 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001891 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001892 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001893 case XML_RELAXNG_ERR_DUPID:
1894 snprintf(msg, 1000, "ID %s redefined", arg1);
1895 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001896 case XML_RELAXNG_ERR_TYPECMP:
1897 snprintf(msg, 1000, "failed to compare type %s", arg1);
1898 break;
1899 case XML_RELAXNG_ERR_NOSTATE:
1900 return(xmlCharStrdup("Internal error: no state"));
1901 case XML_RELAXNG_ERR_NODEFINE:
1902 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001903 case XML_RELAXNG_ERR_INTERNAL:
1904 snprintf(msg, 1000, "Internal error: %s", arg1);
1905 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001906 case XML_RELAXNG_ERR_LISTEXTRA:
1907 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1908 break;
1909 case XML_RELAXNG_ERR_INTERNODATA:
1910 return(xmlCharStrdup("Internal: interleave block has no data"));
1911 case XML_RELAXNG_ERR_INTERSEQ:
1912 return(xmlCharStrdup("Invalid sequence in interleave"));
1913 case XML_RELAXNG_ERR_INTEREXTRA:
1914 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1915 break;
1916 case XML_RELAXNG_ERR_ELEMNAME:
1917 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1918 break;
1919 case XML_RELAXNG_ERR_ELEMNONS:
1920 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1921 break;
1922 case XML_RELAXNG_ERR_ELEMWRONGNS:
1923 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1924 arg1, arg2);
1925 break;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00001926 case XML_RELAXNG_ERR_ELEMWRONG:
1927 snprintf(msg, 1000, "Did not expect element %s there",
1928 arg1);
1929 break;
1930 case XML_RELAXNG_ERR_TEXTWRONG:
1931 snprintf(msg, 1000, "Did not expect text in element %s content",
1932 arg1);
1933 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001934 case XML_RELAXNG_ERR_ELEMEXTRANS:
1935 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1936 break;
1937 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1938 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1939 break;
1940 case XML_RELAXNG_ERR_NOELEM:
1941 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1942 break;
1943 case XML_RELAXNG_ERR_NOTELEM:
1944 return(xmlCharStrdup("Expecting an element got text"));
1945 case XML_RELAXNG_ERR_ATTRVALID:
1946 snprintf(msg, 1000, "Element %s failed to validate attributes",
1947 arg1);
1948 break;
1949 case XML_RELAXNG_ERR_CONTENTVALID:
1950 snprintf(msg, 1000, "Element %s failed to validate content",
1951 arg1);
1952 break;
1953 case XML_RELAXNG_ERR_EXTRACONTENT:
1954 snprintf(msg, 1000, "Element %s has extra content: %s",
1955 arg1, arg2);
1956 break;
1957 case XML_RELAXNG_ERR_INVALIDATTR:
1958 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1959 arg1, arg2);
1960 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001961 case XML_RELAXNG_ERR_LACKDATA:
1962 snprintf(msg, 1000, "Datatype element %s contains no data",
1963 arg1);
1964 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001965 case XML_RELAXNG_ERR_DATAELEM:
1966 snprintf(msg, 1000, "Datatype element %s has child elements",
1967 arg1);
1968 break;
1969 case XML_RELAXNG_ERR_VALELEM:
1970 snprintf(msg, 1000, "Value element %s has child elements",
1971 arg1);
1972 break;
1973 case XML_RELAXNG_ERR_LISTELEM:
1974 snprintf(msg, 1000, "List element %s has child elements",
1975 arg1);
1976 break;
1977 case XML_RELAXNG_ERR_DATATYPE:
1978 snprintf(msg, 1000, "Error validating datatype %s",
1979 arg1);
1980 break;
1981 case XML_RELAXNG_ERR_VALUE:
1982 snprintf(msg, 1000, "Error validating value %s",
1983 arg1);
1984 break;
1985 case XML_RELAXNG_ERR_LIST:
1986 return(xmlCharStrdup("Error validating list"));
1987 case XML_RELAXNG_ERR_NOGRAMMAR:
1988 return(xmlCharStrdup("No top grammar defined"));
1989 case XML_RELAXNG_ERR_EXTRADATA:
1990 return(xmlCharStrdup("Extra data in the document"));
1991 default:
1992 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001993 }
1994 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001995 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001996 }
1997 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001998 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001999}
2000
2001/**
2002 * xmlRelaxNGValidErrorContext:
2003 * @ctxt: the validation context
2004 * @node: the node
2005 * @child: the node child generating the problem.
2006 *
2007 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00002008 */
2009static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00002010xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
2011 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00002012{
2013 int line = 0;
2014 const xmlChar *file = NULL;
2015 const xmlChar *name = NULL;
2016 const char *type = "error";
2017
2018 if ((ctxt == NULL) || (ctxt->error == NULL))
2019 return;
2020
2021 if (child != NULL)
2022 node = child;
2023
2024 if (node != NULL) {
2025 if ((node->type == XML_DOCUMENT_NODE) ||
2026 (node->type == XML_HTML_DOCUMENT_NODE)) {
2027 xmlDocPtr doc = (xmlDocPtr) node;
2028
2029 file = doc->URL;
2030 } else {
2031 /*
2032 * Try to find contextual informations to report
2033 */
2034 if (node->type == XML_ELEMENT_NODE) {
2035 line = (int) node->content;
2036 } else if ((node->prev != NULL) &&
2037 (node->prev->type == XML_ELEMENT_NODE)) {
2038 line = (int) node->prev->content;
2039 } else if ((node->parent != NULL) &&
2040 (node->parent->type == XML_ELEMENT_NODE)) {
2041 line = (int) node->parent->content;
2042 }
2043 if ((node->doc != NULL) && (node->doc->URL != NULL))
2044 file = node->doc->URL;
2045 if (node->name != NULL)
2046 name = node->name;
2047 }
2048 }
2049
Daniel Veillard42f12e92003-03-07 18:32:59 +00002050 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002051
2052 if ((file != NULL) && (line != 0) && (name != NULL))
2053 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2054 type, file, line, name);
2055 else if ((file != NULL) && (name != NULL))
2056 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2057 type, file, name);
2058 else if ((file != NULL) && (line != 0))
2059 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2060 else if (file != NULL)
2061 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2062 else if (name != NULL)
2063 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2064 else
2065 ctxt->error(ctxt->userData, "%s\n", type);
2066}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002067
2068/**
2069 * xmlRelaxNGShowValidError:
2070 * @ctxt: the validation context
2071 * @err: the error number
2072 * @node: the node
2073 * @child: the node child generating the problem.
2074 * @arg1: the first argument
2075 * @arg2: the second argument
2076 *
2077 * Show a validation error.
2078 */
2079static void
2080xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2081 xmlNodePtr node, xmlNodePtr child,
2082 const xmlChar *arg1, const xmlChar *arg2)
2083{
2084 xmlChar *msg;
2085
2086 if (ctxt->error == NULL)
2087 return;
2088
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002089#ifdef DEBUG_ERROR
2090 xmlGenericError(xmlGenericErrorContext,
2091 "Show error %d\n", err);
2092#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002093 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2094 if (msg == NULL)
2095 return;
2096
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002097 if (ctxt->errNo == XML_RELAXNG_OK)
2098 ctxt->errNo = err;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002099 xmlRelaxNGValidErrorContext(ctxt, node, child);
2100 ctxt->error(ctxt->userData, "%s\n", msg);
2101 xmlFree(msg);
2102}
2103
2104/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002105 * xmlRelaxNGPopErrors:
2106 * @ctxt: the validation context
2107 * @level: the error level in the stack
2108 *
2109 * pop and discard all errors until the given level is reached
2110 */
2111static void
2112xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2113 int i;
2114 xmlRelaxNGValidErrorPtr err;
2115
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002116#ifdef DEBUG_ERROR
2117 xmlGenericError(xmlGenericErrorContext,
2118 "Pop errors till level %d\n", level);
2119#endif
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002120 for (i = level;i < ctxt->errNr;i++) {
2121 err = &ctxt->errTab[i];
2122 if (err->flags & ERROR_IS_DUP) {
2123 if (err->arg1 != NULL)
2124 xmlFree((xmlChar *)err->arg1);
2125 err->arg1 = NULL;
2126 if (err->arg2 != NULL)
2127 xmlFree((xmlChar *)err->arg2);
2128 err->arg2 = NULL;
2129 err->flags = 0;
2130 }
2131 }
2132 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002133 if (ctxt->errNr <= 0)
2134 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002135}
2136/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002137 * xmlRelaxNGDumpValidError:
2138 * @ctxt: the validation context
2139 *
2140 * Show all validation error over a given index.
2141 */
2142static void
2143xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002144 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002145 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002146
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002147#ifdef DEBUG_ERROR
2148 xmlGenericError(xmlGenericErrorContext,
2149 "Dumping error stack %d errors\n", ctxt->errNr);
2150#endif
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002151 for (i = 0, k = 0;i < ctxt->errNr;i++) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00002152 err = &ctxt->errTab[i];
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002153 if (k < MAX_ERROR) {
2154 for (j = 0;j < i;j++) {
2155 dup = &ctxt->errTab[j];
2156 if ((err->err == dup->err) && (err->node == dup->node) &&
2157 (xmlStrEqual(err->arg1, dup->arg1)) &&
2158 (xmlStrEqual(err->arg2, dup->arg2))) {
2159 goto skip;
2160 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002161 }
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002162 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2163 err->arg1, err->arg2);
2164 k++;
Daniel Veillard580ced82003-03-21 21:22:48 +00002165 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002166skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002167 if (err->flags & ERROR_IS_DUP) {
2168 if (err->arg1 != NULL)
2169 xmlFree((xmlChar *)err->arg1);
2170 err->arg1 = NULL;
2171 if (err->arg2 != NULL)
2172 xmlFree((xmlChar *)err->arg2);
2173 err->arg2 = NULL;
2174 err->flags = 0;
2175 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002176 }
2177 ctxt->errNr = 0;
2178}
2179/**
2180 * xmlRelaxNGAddValidError:
2181 * @ctxt: the validation context
2182 * @err: the error number
2183 * @arg1: the first argument
2184 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002185 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002186 *
2187 * Register a validation error, either generating it if it's sure
2188 * or stacking it for later handling if unsure.
2189 */
2190static void
2191xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002192 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002193{
2194 if ((ctxt == NULL) || (ctxt->error == NULL))
2195 return;
2196
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002197#ifdef DEBUG_ERROR
2198 xmlGenericError(xmlGenericErrorContext,
2199 "Adding error %d\n", err);
2200#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002201 /*
2202 * generate the error directly
2203 */
2204 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2205 xmlNodePtr node, seq;
2206 /*
2207 * Flush first any stacked error which might be the
2208 * real cause of the problem.
2209 */
2210 if (ctxt->errNr != 0)
2211 xmlRelaxNGDumpValidError(ctxt);
2212 if (ctxt->state != NULL) {
2213 node = ctxt->state->node;
2214 seq = ctxt->state->seq;
2215 } else {
2216 node = seq = NULL;
2217 }
2218 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2219 }
2220 /*
2221 * Stack the error for later processing if needed
2222 */
2223 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002224 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002225 }
2226}
2227
Daniel Veillard6eadf632003-01-23 18:29:16 +00002228
2229/************************************************************************
2230 * *
2231 * Type library hooks *
2232 * *
2233 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002234static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2235 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002236
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002237/**
2238 * xmlRelaxNGSchemaTypeHave:
2239 * @data: data needed for the library
2240 * @type: the type name
2241 *
2242 * Check if the given type is provided by
2243 * the W3C XMLSchema Datatype library.
2244 *
2245 * Returns 1 if yes, 0 if no and -1 in case of error.
2246 */
2247static int
2248xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002249 const xmlChar *type) {
2250 xmlSchemaTypePtr typ;
2251
2252 if (type == NULL)
2253 return(-1);
2254 typ = xmlSchemaGetPredefinedType(type,
2255 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2256 if (typ == NULL)
2257 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002258 return(1);
2259}
2260
2261/**
2262 * xmlRelaxNGSchemaTypeCheck:
2263 * @data: data needed for the library
2264 * @type: the type name
2265 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002266 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002267 *
2268 * Check if the given type and value are validated by
2269 * the W3C XMLSchema Datatype library.
2270 *
2271 * Returns 1 if yes, 0 if no and -1 in case of error.
2272 */
2273static int
2274xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002275 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002276 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002277 void **result,
2278 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002279 xmlSchemaTypePtr typ;
2280 int ret;
2281
2282 /*
2283 * TODO: the type should be cached ab provided back, interface subject
2284 * to changes.
2285 * TODO: handle facets, may require an additional interface and keep
2286 * the value returned from the validation.
2287 */
2288 if ((type == NULL) || (value == NULL))
2289 return(-1);
2290 typ = xmlSchemaGetPredefinedType(type,
2291 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2292 if (typ == NULL)
2293 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002294 ret = xmlSchemaValPredefTypeNode(typ, value,
2295 (xmlSchemaValPtr *) result, node);
2296 if (ret == 2) /* special ID error code */
2297 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002298 if (ret == 0)
2299 return(1);
2300 if (ret > 0)
2301 return(0);
2302 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002303}
2304
2305/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002306 * xmlRelaxNGSchemaFacetCheck:
2307 * @data: data needed for the library
2308 * @type: the type name
2309 * @facet: the facet name
2310 * @val: the facet value
2311 * @strval: the string value
2312 * @value: the value to check
2313 *
2314 * Function provided by a type library to check a value facet
2315 *
2316 * Returns 1 if yes, 0 if no and -1 in case of error.
2317 */
2318static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002319xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002320 const xmlChar *facetname, const xmlChar *val,
2321 const xmlChar *strval, void *value) {
2322 xmlSchemaFacetPtr facet;
2323 xmlSchemaTypePtr typ;
2324 int ret;
2325
2326 if ((type == NULL) || (strval == NULL))
2327 return(-1);
2328 typ = xmlSchemaGetPredefinedType(type,
2329 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2330 if (typ == NULL)
2331 return(-1);
2332
2333 facet = xmlSchemaNewFacet();
2334 if (facet == NULL)
2335 return(-1);
2336
2337 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2338 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2339 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2340 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2341 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2342 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2343 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2344 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2345 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2346 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2347 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2348 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2349 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2350 facet->type = XML_SCHEMA_FACET_PATTERN;
2351 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2352 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2353 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2354 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2355 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2356 facet->type = XML_SCHEMA_FACET_LENGTH;
2357 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2358 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2359 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2360 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2361 } else {
2362 xmlSchemaFreeFacet(facet);
2363 return(-1);
2364 }
2365 facet->value = xmlStrdup(val);
2366 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2367 if (ret != 0) {
2368 xmlSchemaFreeFacet(facet);
2369 return(-1);
2370 }
2371 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2372 xmlSchemaFreeFacet(facet);
2373 if (ret != 0)
2374 return(-1);
2375 return(0);
2376}
2377
2378/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002379 * xmlRelaxNGSchemaFreeValue:
2380 * @data: data needed for the library
2381 * @value: the value to free
2382 *
2383 * Function provided by a type library to free a Schemas value
2384 *
2385 * Returns 1 if yes, 0 if no and -1 in case of error.
2386 */
2387static void
2388xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2389 xmlSchemaFreeValue(value);
2390}
2391
2392/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002393 * xmlRelaxNGSchemaTypeCompare:
2394 * @data: data needed for the library
2395 * @type: the type name
2396 * @value1: the first value
2397 * @value2: the second value
2398 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002399 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002400 * Datatype library.
2401 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002402 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002403 */
2404static int
2405xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002406 const xmlChar *type,
2407 const xmlChar *value1,
2408 xmlNodePtr ctxt1,
2409 void *comp1,
2410 const xmlChar *value2,
2411 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002412 int ret;
2413 xmlSchemaTypePtr typ;
2414 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2415
2416 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2417 return(-1);
2418 typ = xmlSchemaGetPredefinedType(type,
2419 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2420 if (typ == NULL)
2421 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002422 if (comp1 == NULL) {
2423 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2424 if (ret != 0)
2425 return(-1);
2426 if (res1 == NULL)
2427 return(-1);
2428 } else {
2429 res1 = (xmlSchemaValPtr) comp1;
2430 }
2431 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002432 if (ret != 0) {
2433 xmlSchemaFreeValue(res1);
2434 return(-1);
2435 }
2436 if (res1 == NULL) {
2437 xmlSchemaFreeValue(res1);
2438 return(-1);
2439 }
2440 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002441 if (res1 != (xmlSchemaValPtr) comp1)
2442 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002443 xmlSchemaFreeValue(res2);
2444 if (ret == -2)
2445 return(-1);
2446 if (ret == 0)
2447 return(1);
2448 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002449}
2450
2451/**
2452 * xmlRelaxNGDefaultTypeHave:
2453 * @data: data needed for the library
2454 * @type: the type name
2455 *
2456 * Check if the given type is provided by
2457 * the default datatype library.
2458 *
2459 * Returns 1 if yes, 0 if no and -1 in case of error.
2460 */
2461static int
2462xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2463 if (type == NULL)
2464 return(-1);
2465 if (xmlStrEqual(type, BAD_CAST "string"))
2466 return(1);
2467 if (xmlStrEqual(type, BAD_CAST "token"))
2468 return(1);
2469 return(0);
2470}
2471
2472/**
2473 * xmlRelaxNGDefaultTypeCheck:
2474 * @data: data needed for the library
2475 * @type: the type name
2476 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002477 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002478 *
2479 * Check if the given type and value are validated by
2480 * the default datatype library.
2481 *
2482 * Returns 1 if yes, 0 if no and -1 in case of error.
2483 */
2484static int
2485xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2486 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002487 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002488 void **result ATTRIBUTE_UNUSED,
2489 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002490 if (value == NULL)
2491 return(-1);
2492 if (xmlStrEqual(type, BAD_CAST "string"))
2493 return(1);
2494 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002495 return(1);
2496 }
2497
2498 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002499}
2500
2501/**
2502 * xmlRelaxNGDefaultTypeCompare:
2503 * @data: data needed for the library
2504 * @type: the type name
2505 * @value1: the first value
2506 * @value2: the second value
2507 *
2508 * Compare two values accordingly a type from the default
2509 * datatype library.
2510 *
2511 * Returns 1 if yes, 0 if no and -1 in case of error.
2512 */
2513static int
2514xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002515 const xmlChar *type,
2516 const xmlChar *value1,
2517 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2518 void *comp1 ATTRIBUTE_UNUSED,
2519 const xmlChar *value2,
2520 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002521 int ret = -1;
2522
2523 if (xmlStrEqual(type, BAD_CAST "string")) {
2524 ret = xmlStrEqual(value1, value2);
2525 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2526 if (!xmlStrEqual(value1, value2)) {
2527 xmlChar *nval, *nvalue;
2528
2529 /*
2530 * TODO: trivial optimizations are possible by
2531 * computing at compile-time
2532 */
2533 nval = xmlRelaxNGNormalize(NULL, value1);
2534 nvalue = xmlRelaxNGNormalize(NULL, value2);
2535
Daniel Veillardd4310742003-02-18 21:12:46 +00002536 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002537 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002538 else if (xmlStrEqual(nval, nvalue))
2539 ret = 1;
2540 else
2541 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002542 if (nval != NULL)
2543 xmlFree(nval);
2544 if (nvalue != NULL)
2545 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002546 } else
2547 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002548 }
2549 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002550}
2551
2552static int xmlRelaxNGTypeInitialized = 0;
2553static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2554
2555/**
2556 * xmlRelaxNGFreeTypeLibrary:
2557 * @lib: the type library structure
2558 * @namespace: the URI bound to the library
2559 *
2560 * Free the structure associated to the type library
2561 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002562static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002563xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2564 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2565 if (lib == NULL)
2566 return;
2567 if (lib->namespace != NULL)
2568 xmlFree((xmlChar *)lib->namespace);
2569 xmlFree(lib);
2570}
2571
2572/**
2573 * xmlRelaxNGRegisterTypeLibrary:
2574 * @namespace: the URI bound to the library
2575 * @data: data associated to the library
2576 * @have: the provide function
2577 * @check: the checking function
2578 * @comp: the comparison function
2579 *
2580 * Register a new type library
2581 *
2582 * Returns 0 in case of success and -1 in case of error.
2583 */
2584static int
2585xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2586 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002587 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2588 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002589 xmlRelaxNGTypeLibraryPtr lib;
2590 int ret;
2591
2592 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2593 (check == NULL) || (comp == NULL))
2594 return(-1);
2595 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2596 xmlGenericError(xmlGenericErrorContext,
2597 "Relax-NG types library '%s' already registered\n",
2598 namespace);
2599 return(-1);
2600 }
2601 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2602 if (lib == NULL) {
2603 xmlGenericError(xmlGenericErrorContext,
2604 "Relax-NG types library '%s' malloc() failed\n",
2605 namespace);
2606 return (-1);
2607 }
2608 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2609 lib->namespace = xmlStrdup(namespace);
2610 lib->data = data;
2611 lib->have = have;
2612 lib->comp = comp;
2613 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002614 lib->facet = facet;
2615 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002616 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2617 if (ret < 0) {
2618 xmlGenericError(xmlGenericErrorContext,
2619 "Relax-NG types library failed to register '%s'\n",
2620 namespace);
2621 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2622 return(-1);
2623 }
2624 return(0);
2625}
2626
2627/**
2628 * xmlRelaxNGInitTypes:
2629 *
2630 * Initilize the default type libraries.
2631 *
2632 * Returns 0 in case of success and -1 in case of error.
2633 */
2634static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002635xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002636 if (xmlRelaxNGTypeInitialized != 0)
2637 return(0);
2638 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2639 if (xmlRelaxNGRegisteredTypes == NULL) {
2640 xmlGenericError(xmlGenericErrorContext,
2641 "Failed to allocate sh table for Relax-NG types\n");
2642 return(-1);
2643 }
2644 xmlRelaxNGRegisterTypeLibrary(
2645 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2646 NULL,
2647 xmlRelaxNGSchemaTypeHave,
2648 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002649 xmlRelaxNGSchemaTypeCompare,
2650 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002651 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002652 xmlRelaxNGRegisterTypeLibrary(
2653 xmlRelaxNGNs,
2654 NULL,
2655 xmlRelaxNGDefaultTypeHave,
2656 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002657 xmlRelaxNGDefaultTypeCompare,
2658 NULL,
2659 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002660 xmlRelaxNGTypeInitialized = 1;
2661 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002662}
2663
2664/**
2665 * xmlRelaxNGCleanupTypes:
2666 *
2667 * Cleanup the default Schemas type library associated to RelaxNG
2668 */
2669void
2670xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002671 if (xmlRelaxNGTypeInitialized == 0)
2672 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002673 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002674 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2675 xmlRelaxNGFreeTypeLibrary);
2676 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002677}
2678
2679/************************************************************************
2680 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002681 * Compiling element content into regexp *
2682 * *
2683 * Sometime the element content can be compiled into a pure regexp, *
2684 * This allows a faster execution and streamability at that level *
2685 * *
2686 ************************************************************************/
2687
Daniel Veillard52b48c72003-04-13 19:53:42 +00002688static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2689 xmlRelaxNGDefinePtr def);
2690
Daniel Veillard952379b2003-03-17 15:37:12 +00002691/**
2692 * xmlRelaxNGIsCompileable:
2693 * @define: the definition to check
2694 *
2695 * Check if a definition is nullable.
2696 *
2697 * Returns 1 if yes, 0 if no and -1 in case of error
2698 */
2699static int
2700xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00002701 int ret = -1;
2702
Daniel Veillard952379b2003-03-17 15:37:12 +00002703 if (def == NULL) {
2704 return(-1);
2705 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002706 if ((def->type != XML_RELAXNG_ELEMENT) &&
2707 (def->dflags & IS_COMPILABLE))
2708 return(1);
2709 if ((def->type != XML_RELAXNG_ELEMENT) &&
2710 (def->dflags & IS_NOT_COMPILABLE))
2711 return(0);
Daniel Veillard952379b2003-03-17 15:37:12 +00002712 switch(def->type) {
2713 case XML_RELAXNG_REF:
2714 case XML_RELAXNG_EXTERNALREF:
2715 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002716 if (def->depth == -20) {
2717 return(1);
2718 } else {
2719 def->depth = -20;
2720 ret = xmlRelaxNGIsCompileable(def->content);
2721 }
2722 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002723 case XML_RELAXNG_NOOP:
2724 case XML_RELAXNG_START:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002725 ret = xmlRelaxNGIsCompileable(def->content);
2726 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002727 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002728 case XML_RELAXNG_EMPTY:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002729 ret = 1;
2730 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002731 case XML_RELAXNG_ELEMENT:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002732 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2733 ((def->dflags & IS_COMPILABLE) == 0)) {
2734 ret = xmlRelaxNGIsCompileable(def->content);
2735 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2736 if (ret == 1) def->dflags |= IS_COMPILABLE;
2737 }
2738 if ((def->nameClass != NULL) || (def->name == NULL))
2739 return(0);
2740 else
2741 return(1);
2742 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002743 case XML_RELAXNG_OPTIONAL:
2744 case XML_RELAXNG_ZEROORMORE:
2745 case XML_RELAXNG_ONEORMORE:
2746 case XML_RELAXNG_CHOICE:
2747 case XML_RELAXNG_GROUP:
2748 case XML_RELAXNG_DEF: {
2749 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002750
2751 list = def->content;
2752 while (list != NULL) {
2753 ret = xmlRelaxNGIsCompileable(list);
2754 if (ret != 1)
Daniel Veillard52b48c72003-04-13 19:53:42 +00002755 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002756 list = list->next;
2757 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002758 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002759 }
2760 case XML_RELAXNG_EXCEPT:
2761 case XML_RELAXNG_ATTRIBUTE:
2762 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002763 case XML_RELAXNG_DATATYPE:
2764 case XML_RELAXNG_LIST:
2765 case XML_RELAXNG_PARAM:
2766 case XML_RELAXNG_VALUE:
2767 ret = 0;
2768 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002769 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002770 ret = -1;
2771 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002772 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002773 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2774 if (ret == 1) def->dflags |= IS_COMPILABLE;
2775 return(ret);
2776}
2777
2778/**
2779 * xmlRelaxNGCompile:
2780 * ctxt: the RelaxNG parser context
2781 * @define: the definition tree to compile
2782 *
2783 * Compile the set of definitions, it works recursively, till the
2784 * element boundaries, where it tries to compile the content if possible
2785 *
2786 * Returns 0 if success and -1 in case of error
2787 */
2788static int
2789xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2790 int ret = 0;
2791 xmlRelaxNGDefinePtr list;
2792
2793 if ((ctxt == NULL) || (def == NULL)) return(-1);
2794
2795 switch(def->type) {
2796 case XML_RELAXNG_START:
2797 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
2798 xmlAutomataPtr oldam = ctxt->am;
2799 xmlAutomataStatePtr oldstate = ctxt->state;
2800
2801 def->depth = -25;
2802
2803 list = def->content;
2804 ctxt->am = xmlNewAutomata();
2805 if (ctxt->am == NULL)
2806 return(-1);
2807 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2808 while (list != NULL) {
2809 xmlRelaxNGCompile(ctxt, list);
2810 list = list->next;
2811 }
2812 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2813 def->contModel = xmlAutomataCompile(ctxt->am);
2814 xmlRegexpIsDeterminist(def->contModel);
2815
2816 xmlFreeAutomata(ctxt->am);
2817 ctxt->state = oldstate;
2818 ctxt->am = oldam;
2819 }
2820 break;
2821 case XML_RELAXNG_ELEMENT:
2822 if ((ctxt->am != NULL) && (def->name != NULL)) {
2823 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002824 ctxt->state, NULL, def->name, def->ns, def);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002825 }
2826 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2827 xmlAutomataPtr oldam = ctxt->am;
2828 xmlAutomataStatePtr oldstate = ctxt->state;
2829
2830 def->depth = -25;
2831
2832 list = def->content;
2833 ctxt->am = xmlNewAutomata();
2834 if (ctxt->am == NULL)
2835 return(-1);
2836 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2837 while (list != NULL) {
2838 xmlRelaxNGCompile(ctxt, list);
2839 list = list->next;
2840 }
2841 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2842 def->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002843 if (!xmlRegexpIsDeterminist(def->contModel)) {
2844 /*
2845 * we can only use the automata if it is determinist
2846 */
2847 xmlRegFreeRegexp(def->contModel);
2848 def->contModel = NULL;
2849 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002850 xmlFreeAutomata(ctxt->am);
2851 ctxt->state = oldstate;
2852 ctxt->am = oldam;
2853 } else {
2854 xmlAutomataPtr oldam = ctxt->am;
2855
2856 /*
2857 * we can't build the content model for this element content
2858 * but it still might be possible to build it for some of its
2859 * children, recurse.
2860 */
2861 ret = xmlRelaxNGTryCompile(ctxt, def);
2862 ctxt->am = oldam;
2863 }
2864 break;
2865 case XML_RELAXNG_REF:
2866 case XML_RELAXNG_EXTERNALREF:
2867 case XML_RELAXNG_PARENTREF:
2868 case XML_RELAXNG_NOOP:
2869 ret = xmlRelaxNGCompile(ctxt, def->content);
2870 break;
2871 case XML_RELAXNG_OPTIONAL: {
2872 xmlAutomataStatePtr oldstate = ctxt->state;
2873
2874 xmlRelaxNGCompile(ctxt, def->content);
2875 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2876 break;
2877 }
2878 case XML_RELAXNG_ZEROORMORE: {
2879 xmlAutomataStatePtr oldstate;
2880
2881 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2882 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002883 list = def->content;
2884 while (list != NULL) {
2885 xmlRelaxNGCompile(ctxt, list);
2886 list = list->next;
2887 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002888 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2889 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2890 break;
2891 }
2892 case XML_RELAXNG_ONEORMORE: {
2893 xmlAutomataStatePtr oldstate;
2894
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002895 list = def->content;
2896 while (list != NULL) {
2897 xmlRelaxNGCompile(ctxt, list);
2898 list = list->next;
2899 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002900 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002901 list = def->content;
2902 while (list != NULL) {
2903 xmlRelaxNGCompile(ctxt, list);
2904 list = list->next;
2905 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002906 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2907 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2908 break;
2909 }
2910 case XML_RELAXNG_CHOICE: {
2911 xmlAutomataStatePtr target = NULL;
2912 xmlAutomataStatePtr oldstate = ctxt->state;
2913
2914 list = def->content;
2915 while (list != NULL) {
2916 ctxt->state = oldstate;
2917 xmlRelaxNGCompile(ctxt, list);
2918 if (target == NULL)
2919 target = ctxt->state;
2920 else {
2921 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, target);
2922 }
2923 list = list->next;
2924 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002925 ctxt->state = target;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002926
2927 break;
2928 }
2929 case XML_RELAXNG_GROUP:
2930 case XML_RELAXNG_DEF:
2931 list = def->content;
2932 while (list != NULL) {
2933 xmlRelaxNGCompile(ctxt, list);
2934 list = list->next;
2935 }
2936 break;
2937 case XML_RELAXNG_TEXT: {
2938 xmlAutomataStatePtr oldstate;
2939
2940 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2941 oldstate = ctxt->state;
2942 xmlRelaxNGCompile(ctxt, def->content);
2943 xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state,
2944 BAD_CAST "#text", NULL);
2945 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2946 break;
2947 }
2948 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002949 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002950 break;
2951 case XML_RELAXNG_EXCEPT:
2952 case XML_RELAXNG_ATTRIBUTE:
2953 case XML_RELAXNG_INTERLEAVE:
2954 case XML_RELAXNG_NOT_ALLOWED:
2955 case XML_RELAXNG_DATATYPE:
2956 case XML_RELAXNG_LIST:
2957 case XML_RELAXNG_PARAM:
2958 case XML_RELAXNG_VALUE:
2959 TODO /* This should not happen and generate an internal error */
2960 printf("trying to compile %s\n", xmlRelaxNGDefName(def));
2961
2962 break;
2963 }
2964 return(ret);
2965}
2966
2967/**
2968 * xmlRelaxNGTryCompile:
2969 * ctxt: the RelaxNG parser context
2970 * @define: the definition tree to compile
2971 *
2972 * Try to compile the set of definitions, it works recursively,
2973 * possibly ignoring parts which cannot be compiled.
2974 *
2975 * Returns 0 if success and -1 in case of error
2976 */
2977static int
2978xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2979 int ret = 0;
2980 xmlRelaxNGDefinePtr list;
2981
2982 if ((ctxt == NULL) || (def == NULL)) return(-1);
2983
2984 if ((def->type == XML_RELAXNG_START) ||
2985 (def->type == XML_RELAXNG_ELEMENT)) {
2986 ret = xmlRelaxNGIsCompileable(def);
2987 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2988 ctxt->am = NULL;
2989 ret = xmlRelaxNGCompile(ctxt, def);
2990 return(ret);
2991 }
2992 }
2993 switch(def->type) {
2994 case XML_RELAXNG_REF:
2995 case XML_RELAXNG_EXTERNALREF:
2996 case XML_RELAXNG_PARENTREF:
2997 case XML_RELAXNG_NOOP:
2998 case XML_RELAXNG_START:
2999 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3000 break;
3001 case XML_RELAXNG_TEXT:
3002 case XML_RELAXNG_DATATYPE:
3003 case XML_RELAXNG_LIST:
3004 case XML_RELAXNG_PARAM:
3005 case XML_RELAXNG_VALUE:
3006 case XML_RELAXNG_EMPTY:
3007 case XML_RELAXNG_ELEMENT:
3008 ret = 0;
3009 break;
3010 case XML_RELAXNG_OPTIONAL:
3011 case XML_RELAXNG_ZEROORMORE:
3012 case XML_RELAXNG_ONEORMORE:
3013 case XML_RELAXNG_CHOICE:
3014 case XML_RELAXNG_GROUP:
3015 case XML_RELAXNG_DEF:
3016 list = def->content;
3017 while (list != NULL) {
3018 ret = xmlRelaxNGTryCompile(ctxt, list);
3019 if (ret != 0)
3020 break;
3021 list = list->next;
3022 }
3023 break;
3024 case XML_RELAXNG_EXCEPT:
3025 case XML_RELAXNG_ATTRIBUTE:
3026 case XML_RELAXNG_INTERLEAVE:
3027 case XML_RELAXNG_NOT_ALLOWED:
3028 ret = 0;
3029 break;
3030 }
3031 return(ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003032}
3033
3034/************************************************************************
3035 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003036 * Parsing functions *
3037 * *
3038 ************************************************************************/
3039
3040static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
3041 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3042static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
3043 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3044static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00003045 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003046static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
3047 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003048static xmlRelaxNGPtr xmlRelaxNGParseDocument(
3049 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003050static int xmlRelaxNGParseGrammarContent(
3051 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003052static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
3053 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3054 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00003055static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
3056 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003057static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3058 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003059
3060
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003061#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003062
3063/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003064 * xmlRelaxNGIsNullable:
3065 * @define: the definition to verify
3066 *
3067 * Check if a definition is nullable.
3068 *
3069 * Returns 1 if yes, 0 if no and -1 in case of error
3070 */
3071static int
3072xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
3073 int ret;
3074 if (define == NULL)
3075 return(-1);
3076
Daniel Veillarde063f482003-03-21 16:53:17 +00003077 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003078 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003079 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003080 return(0);
3081 switch (define->type) {
3082 case XML_RELAXNG_EMPTY:
3083 case XML_RELAXNG_TEXT:
3084 ret = 1; break;
3085 case XML_RELAXNG_NOOP:
3086 case XML_RELAXNG_DEF:
3087 case XML_RELAXNG_REF:
3088 case XML_RELAXNG_EXTERNALREF:
3089 case XML_RELAXNG_PARENTREF:
3090 case XML_RELAXNG_ONEORMORE:
3091 ret = xmlRelaxNGIsNullable(define->content);
3092 break;
3093 case XML_RELAXNG_EXCEPT:
3094 case XML_RELAXNG_NOT_ALLOWED:
3095 case XML_RELAXNG_ELEMENT:
3096 case XML_RELAXNG_DATATYPE:
3097 case XML_RELAXNG_PARAM:
3098 case XML_RELAXNG_VALUE:
3099 case XML_RELAXNG_LIST:
3100 case XML_RELAXNG_ATTRIBUTE:
3101 ret = 0; break;
3102 case XML_RELAXNG_CHOICE: {
3103 xmlRelaxNGDefinePtr list = define->content;
3104
3105 while (list != NULL) {
3106 ret = xmlRelaxNGIsNullable(list);
3107 if (ret != 0)
3108 goto done;
3109 list = list->next;
3110 }
3111 ret = 0; break;
3112 }
3113 case XML_RELAXNG_START:
3114 case XML_RELAXNG_INTERLEAVE:
3115 case XML_RELAXNG_GROUP: {
3116 xmlRelaxNGDefinePtr list = define->content;
3117
3118 while (list != NULL) {
3119 ret = xmlRelaxNGIsNullable(list);
3120 if (ret != 1)
3121 goto done;
3122 list = list->next;
3123 }
3124 return(1);
3125 }
3126 default:
3127 return(-1);
3128 }
3129done:
3130 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003131 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003132 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00003133 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003134 return(ret);
3135}
3136
3137/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003138 * xmlRelaxNGIsBlank:
3139 * @str: a string
3140 *
3141 * Check if a string is ignorable c.f. 4.2. Whitespace
3142 *
3143 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3144 */
3145static int
3146xmlRelaxNGIsBlank(xmlChar *str) {
3147 if (str == NULL)
3148 return(1);
3149 while (*str != 0) {
3150 if (!(IS_BLANK(*str))) return(0);
3151 str++;
3152 }
3153 return(1);
3154}
3155
Daniel Veillard6eadf632003-01-23 18:29:16 +00003156/**
3157 * xmlRelaxNGGetDataTypeLibrary:
3158 * @ctxt: a Relax-NG parser context
3159 * @node: the current data or value element
3160 *
3161 * Applies algorithm from 4.3. datatypeLibrary attribute
3162 *
3163 * Returns the datatypeLibary value or NULL if not found
3164 */
3165static xmlChar *
3166xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3167 xmlNodePtr node) {
3168 xmlChar *ret, *escape;
3169
Daniel Veillard6eadf632003-01-23 18:29:16 +00003170 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3171 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3172 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003173 if (ret[0] == 0) {
3174 xmlFree(ret);
3175 return(NULL);
3176 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003177 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00003178 if (escape == NULL) {
3179 return(ret);
3180 }
3181 xmlFree(ret);
3182 return(escape);
3183 }
3184 }
3185 node = node->parent;
3186 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003187 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3188 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003189 if (ret[0] == 0) {
3190 xmlFree(ret);
3191 return(NULL);
3192 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003193 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3194 if (escape == NULL) {
3195 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003196 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003197 xmlFree(ret);
3198 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003199 }
3200 node = node->parent;
3201 }
3202 return(NULL);
3203}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003204
3205/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003206 * xmlRelaxNGParseValue:
3207 * @ctxt: a Relax-NG parser context
3208 * @node: the data node.
3209 *
3210 * parse the content of a RelaxNG value node.
3211 *
3212 * Returns the definition pointer or NULL in case of error
3213 */
3214static xmlRelaxNGDefinePtr
3215xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3216 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003217 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003218 xmlChar *type;
3219 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003220 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003221
Daniel Veillardfd573f12003-03-16 17:52:32 +00003222 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003223 if (def == NULL)
3224 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003225 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003226
3227 type = xmlGetProp(node, BAD_CAST "type");
3228 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003229 xmlRelaxNGNormExtSpace(type);
3230 if (xmlValidateNCName(type, 0)) {
3231 if (ctxt->error != NULL)
3232 ctxt->error(ctxt->userData,
3233 "value type '%s' is not an NCName\n",
3234 type);
3235 ctxt->nbErrors++;
3236 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003237 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3238 if (library == NULL)
3239 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3240
3241 def->name = type;
3242 def->ns = library;
3243
3244 lib = (xmlRelaxNGTypeLibraryPtr)
3245 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3246 if (lib == NULL) {
3247 if (ctxt->error != NULL)
3248 ctxt->error(ctxt->userData,
3249 "Use of unregistered type library '%s'\n",
3250 library);
3251 ctxt->nbErrors++;
3252 def->data = NULL;
3253 } else {
3254 def->data = lib;
3255 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003256 if (ctxt->error != NULL)
3257 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003258 "Internal error with type library '%s': no 'have'\n",
3259 library);
3260 ctxt->nbErrors++;
3261 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003262 success = lib->have(lib->data, def->name);
3263 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003264 if (ctxt->error != NULL)
3265 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003266 "Error type '%s' is not exported by type library '%s'\n",
3267 def->name, library);
3268 ctxt->nbErrors++;
3269 }
3270 }
3271 }
3272 }
3273 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00003274 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003275 } else if (((node->children->type != XML_TEXT_NODE) &&
3276 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00003277 (node->children->next != NULL)) {
3278 if (ctxt->error != NULL)
3279 ctxt->error(ctxt->userData,
3280 "Expecting a single text value for <value>content\n");
3281 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003282 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00003283 def->value = xmlNodeGetContent(node);
3284 if (def->value == NULL) {
3285 if (ctxt->error != NULL)
3286 ctxt->error(ctxt->userData,
3287 "Element <value> has no content\n");
3288 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003289 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3290 void *val = NULL;
3291
3292 success = lib->check(lib->data, def->name, def->value, &val, node);
3293 if (success != 1) {
3294 if (ctxt->error != NULL)
3295 ctxt->error(ctxt->userData,
3296 "Value '%s' is not acceptable for type '%s'\n",
3297 def->value, def->name);
3298 ctxt->nbErrors++;
3299 } else {
3300 if (val != NULL)
3301 def->attrs = val;
3302 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003303 }
3304 }
3305 /* TODO check ahead of time that the value is okay per the type */
3306 return(def);
3307}
3308
3309/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003310 * xmlRelaxNGParseData:
3311 * @ctxt: a Relax-NG parser context
3312 * @node: the data node.
3313 *
3314 * parse the content of a RelaxNG data node.
3315 *
3316 * Returns the definition pointer or NULL in case of error
3317 */
3318static xmlRelaxNGDefinePtr
3319xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003320 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003321 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003322 xmlRelaxNGTypeLibraryPtr lib;
3323 xmlChar *type;
3324 xmlChar *library;
3325 xmlNodePtr content;
3326 int tmp;
3327
3328 type = xmlGetProp(node, BAD_CAST "type");
3329 if (type == NULL) {
3330 if (ctxt->error != NULL)
3331 ctxt->error(ctxt->userData,
3332 "data has no type\n");
3333 ctxt->nbErrors++;
3334 return(NULL);
3335 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003336 xmlRelaxNGNormExtSpace(type);
3337 if (xmlValidateNCName(type, 0)) {
3338 if (ctxt->error != NULL)
3339 ctxt->error(ctxt->userData,
3340 "data type '%s' is not an NCName\n",
3341 type);
3342 ctxt->nbErrors++;
3343 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003344 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3345 if (library == NULL)
3346 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3347
Daniel Veillardfd573f12003-03-16 17:52:32 +00003348 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003349 if (def == NULL) {
3350 xmlFree(type);
3351 return(NULL);
3352 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003353 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003354 def->name = type;
3355 def->ns = library;
3356
3357 lib = (xmlRelaxNGTypeLibraryPtr)
3358 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3359 if (lib == NULL) {
3360 if (ctxt->error != NULL)
3361 ctxt->error(ctxt->userData,
3362 "Use of unregistered type library '%s'\n",
3363 library);
3364 ctxt->nbErrors++;
3365 def->data = NULL;
3366 } else {
3367 def->data = lib;
3368 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003369 if (ctxt->error != NULL)
3370 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003371 "Internal error with type library '%s': no 'have'\n",
3372 library);
3373 ctxt->nbErrors++;
3374 } else {
3375 tmp = lib->have(lib->data, def->name);
3376 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003377 if (ctxt->error != NULL)
3378 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003379 "Error type '%s' is not exported by type library '%s'\n",
3380 def->name, library);
3381 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003382 } else if ((xmlStrEqual(library, BAD_CAST
3383 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3384 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3385 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3386 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003387 }
3388 }
3389 }
3390 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003391
3392 /*
3393 * Handle optional params
3394 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003395 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003396 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3397 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003398 if (xmlStrEqual(library,
3399 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3400 if (ctxt->error != NULL)
3401 ctxt->error(ctxt->userData,
3402 "Type library '%s' does not allow type parameters\n",
3403 library);
3404 ctxt->nbErrors++;
3405 content = content->next;
3406 while ((content != NULL) &&
3407 (xmlStrEqual(content->name, BAD_CAST "param")))
3408 content = content->next;
3409 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003410 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003411 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003412 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003413 param->name = xmlGetProp(content, BAD_CAST "name");
3414 if (param->name == NULL) {
3415 if (ctxt->error != NULL)
3416 ctxt->error(ctxt->userData,
3417 "param has no name\n");
3418 ctxt->nbErrors++;
3419 }
3420 param->value = xmlNodeGetContent(content);
3421 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003422 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003423 } else {
3424 lastparam->next = param;
3425 lastparam = param;
3426 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003427 if (lib != NULL) {
3428 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003429 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003430 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003431 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003432 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003433 /*
3434 * Handle optional except
3435 */
3436 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3437 xmlNodePtr child;
3438 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3439
Daniel Veillardfd573f12003-03-16 17:52:32 +00003440 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003441 if (except == NULL) {
3442 return(def);
3443 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003444 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003445 child = content->children;
3446 if (last == NULL) {
3447 def->content = except;
3448 } else {
3449 last->next = except;
3450 }
3451 if (child == NULL) {
3452 if (ctxt->error != NULL)
3453 ctxt->error(ctxt->userData,
3454 "except has no content\n");
3455 ctxt->nbErrors++;
3456 }
3457 while (child != NULL) {
3458 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3459 if (tmp2 != NULL) {
3460 if (last2 == NULL) {
3461 except->content = last2 = tmp2;
3462 } else {
3463 last2->next = tmp2;
3464 last2 = tmp2;
3465 }
3466 }
3467 child = child->next;
3468 }
3469 content = content->next;
3470 }
3471 /*
3472 * Check there is no unhandled data
3473 */
3474 if (content != NULL) {
3475 if (ctxt->error != NULL)
3476 ctxt->error(ctxt->userData,
3477 "Element data has unexpected content %s\n", content->name);
3478 ctxt->nbErrors++;
3479 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003480
3481 return(def);
3482}
3483
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003484static const xmlChar *invalidName = BAD_CAST "\1";
3485
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003486/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003487 * xmlRelaxNGCompareNameClasses:
3488 * @defs1: the first element/attribute defs
3489 * @defs2: the second element/attribute defs
3490 * @name: the restriction on the name
3491 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003492 *
3493 * Compare the 2 lists of element definitions. The comparison is
3494 * that if both lists do not accept the same QNames, it returns 1
3495 * If the 2 lists can accept the same QName the comparison returns 0
3496 *
3497 * Returns 1 disttinct, 0 if equal
3498 */
3499static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003500xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3501 xmlRelaxNGDefinePtr def2) {
3502 int ret = 1;
3503 xmlNode node;
3504 xmlNs ns;
3505 xmlRelaxNGValidCtxt ctxt;
3506 ctxt.flags = FLAGS_IGNORABLE;
3507
Daniel Veillard42f12e92003-03-07 18:32:59 +00003508 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3509
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003510 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3511 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3512 if (def2->type == XML_RELAXNG_TEXT)
3513 return(1);
3514 if (def1->name != NULL) {
3515 node.name = def1->name;
3516 } else {
3517 node.name = invalidName;
3518 }
3519 node.ns = &ns;
3520 if (def1->ns != NULL) {
3521 if (def1->ns[0] == 0) {
3522 node.ns = NULL;
3523 } else {
3524 ns.href = def1->ns;
3525 }
3526 } else {
3527 ns.href = invalidName;
3528 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003529 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003530 if (def1->nameClass != NULL) {
3531 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3532 } else {
3533 ret = 0;
3534 }
3535 } else {
3536 ret = 1;
3537 }
3538 } else if (def1->type == XML_RELAXNG_TEXT) {
3539 if (def2->type == XML_RELAXNG_TEXT)
3540 return(0);
3541 return(1);
3542 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003543 TODO
3544 ret = 0;
3545 } else {
3546 TODO
3547 ret = 0;
3548 }
3549 if (ret == 0)
3550 return(ret);
3551 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3552 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3553 if (def2->name != NULL) {
3554 node.name = def2->name;
3555 } else {
3556 node.name = invalidName;
3557 }
3558 node.ns = &ns;
3559 if (def2->ns != NULL) {
3560 if (def2->ns[0] == 0) {
3561 node.ns = NULL;
3562 } else {
3563 ns.href = def2->ns;
3564 }
3565 } else {
3566 ns.href = invalidName;
3567 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003568 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003569 if (def2->nameClass != NULL) {
3570 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3571 } else {
3572 ret = 0;
3573 }
3574 } else {
3575 ret = 1;
3576 }
3577 } else {
3578 TODO
3579 ret = 0;
3580 }
3581
3582 return(ret);
3583}
3584
3585/**
3586 * xmlRelaxNGCompareElemDefLists:
3587 * @ctxt: a Relax-NG parser context
3588 * @defs1: the first list of element/attribute defs
3589 * @defs2: the second list of element/attribute defs
3590 *
3591 * Compare the 2 lists of element or attribute definitions. The comparison
3592 * is that if both lists do not accept the same QNames, it returns 1
3593 * If the 2 lists can accept the same QName the comparison returns 0
3594 *
3595 * Returns 1 disttinct, 0 if equal
3596 */
3597static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003598xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3599 xmlRelaxNGDefinePtr *def1,
3600 xmlRelaxNGDefinePtr *def2) {
3601 xmlRelaxNGDefinePtr *basedef2 = def2;
3602
Daniel Veillard154877e2003-01-30 12:17:05 +00003603 if ((def1 == NULL) || (def2 == NULL))
3604 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003605 if ((*def1 == NULL) || (*def2 == NULL))
3606 return(1);
3607 while (*def1 != NULL) {
3608 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003609 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3610 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003611 def2++;
3612 }
3613 def2 = basedef2;
3614 def1++;
3615 }
3616 return(1);
3617}
3618
3619/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003620 * xmlRelaxNGGenerateAttributes:
3621 * @ctxt: a Relax-NG parser context
3622 * @def: the definition definition
3623 *
3624 * Check if the definition can only generate attributes
3625 *
3626 * Returns 1 if yes, 0 if no and -1 in case of error.
3627 */
3628static int
3629xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3630 xmlRelaxNGDefinePtr def) {
3631 xmlRelaxNGDefinePtr parent, cur, tmp;
3632
3633 /*
3634 * Don't run that check in case of error. Infinite recursion
3635 * becomes possible.
3636 */
3637 if (ctxt->nbErrors != 0)
3638 return(-1);
3639
3640 parent = NULL;
3641 cur = def;
3642 while (cur != NULL) {
3643 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3644 (cur->type == XML_RELAXNG_TEXT) ||
3645 (cur->type == XML_RELAXNG_DATATYPE) ||
3646 (cur->type == XML_RELAXNG_PARAM) ||
3647 (cur->type == XML_RELAXNG_LIST) ||
3648 (cur->type == XML_RELAXNG_VALUE) ||
3649 (cur->type == XML_RELAXNG_EMPTY))
3650 return(0);
3651 if ((cur->type == XML_RELAXNG_CHOICE) ||
3652 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3653 (cur->type == XML_RELAXNG_GROUP) ||
3654 (cur->type == XML_RELAXNG_ONEORMORE) ||
3655 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3656 (cur->type == XML_RELAXNG_OPTIONAL) ||
3657 (cur->type == XML_RELAXNG_PARENTREF) ||
3658 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3659 (cur->type == XML_RELAXNG_REF) ||
3660 (cur->type == XML_RELAXNG_DEF)) {
3661 if (cur->content != NULL) {
3662 parent = cur;
3663 cur = cur->content;
3664 tmp = cur;
3665 while (tmp != NULL) {
3666 tmp->parent = parent;
3667 tmp = tmp->next;
3668 }
3669 continue;
3670 }
3671 }
3672 if (cur == def)
3673 break;
3674 if (cur->next != NULL) {
3675 cur = cur->next;
3676 continue;
3677 }
3678 do {
3679 cur = cur->parent;
3680 if (cur == NULL) break;
3681 if (cur == def) return(1);
3682 if (cur->next != NULL) {
3683 cur = cur->next;
3684 break;
3685 }
3686 } while (cur != NULL);
3687 }
3688 return(1);
3689}
3690
3691/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003692 * xmlRelaxNGGetElements:
3693 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003694 * @def: the definition definition
3695 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003696 *
3697 * Compute the list of top elements a definition can generate
3698 *
3699 * Returns a list of elements or NULL if none was found.
3700 */
3701static xmlRelaxNGDefinePtr *
3702xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003703 xmlRelaxNGDefinePtr def,
3704 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003705 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003706 int len = 0;
3707 int max = 0;
3708
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003709 /*
3710 * Don't run that check in case of error. Infinite recursion
3711 * becomes possible.
3712 */
3713 if (ctxt->nbErrors != 0)
3714 return(NULL);
3715
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003716 parent = NULL;
3717 cur = def;
3718 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003719 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3720 (cur->type == XML_RELAXNG_TEXT))) ||
3721 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003722 if (ret == NULL) {
3723 max = 10;
3724 ret = (xmlRelaxNGDefinePtr *)
3725 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3726 if (ret == NULL) {
3727 if (ctxt->error != NULL)
3728 ctxt->error(ctxt->userData,
3729 "Out of memory in element search\n");
3730 ctxt->nbErrors++;
3731 return(NULL);
3732 }
3733 } else if (max <= len) {
3734 max *= 2;
3735 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3736 if (ret == NULL) {
3737 if (ctxt->error != NULL)
3738 ctxt->error(ctxt->userData,
3739 "Out of memory in element search\n");
3740 ctxt->nbErrors++;
3741 return(NULL);
3742 }
3743 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003744 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003745 ret[len] = NULL;
3746 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3747 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3748 (cur->type == XML_RELAXNG_GROUP) ||
3749 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003750 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3751 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003752 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003753 (cur->type == XML_RELAXNG_REF) ||
3754 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003755 /*
3756 * Don't go within elements or attributes or string values.
3757 * Just gather the element top list
3758 */
3759 if (cur->content != NULL) {
3760 parent = cur;
3761 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003762 tmp = cur;
3763 while (tmp != NULL) {
3764 tmp->parent = parent;
3765 tmp = tmp->next;
3766 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003767 continue;
3768 }
3769 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003770 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003771 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003772 if (cur->next != NULL) {
3773 cur = cur->next;
3774 continue;
3775 }
3776 do {
3777 cur = cur->parent;
3778 if (cur == NULL) break;
3779 if (cur == def) return(ret);
3780 if (cur->next != NULL) {
3781 cur = cur->next;
3782 break;
3783 }
3784 } while (cur != NULL);
3785 }
3786 return(ret);
3787}
3788
3789/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003790 * xmlRelaxNGCheckChoiceDeterminism:
3791 * @ctxt: a Relax-NG parser context
3792 * @def: the choice definition
3793 *
3794 * Also used to find indeterministic pattern in choice
3795 */
3796static void
3797xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3798 xmlRelaxNGDefinePtr def) {
3799 xmlRelaxNGDefinePtr **list;
3800 xmlRelaxNGDefinePtr cur;
3801 int nbchild = 0, i, j, ret;
3802 int is_nullable = 0;
3803 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003804 xmlHashTablePtr triage = NULL;
3805 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003806
3807 if ((def == NULL) ||
3808 (def->type != XML_RELAXNG_CHOICE))
3809 return;
3810
Daniel Veillarde063f482003-03-21 16:53:17 +00003811 if (def->dflags & IS_PROCESSED)
3812 return;
3813
Daniel Veillardfd573f12003-03-16 17:52:32 +00003814 /*
3815 * Don't run that check in case of error. Infinite recursion
3816 * becomes possible.
3817 */
3818 if (ctxt->nbErrors != 0)
3819 return;
3820
3821 is_nullable = xmlRelaxNGIsNullable(def);
3822
3823 cur = def->content;
3824 while (cur != NULL) {
3825 nbchild++;
3826 cur = cur->next;
3827 }
3828
3829 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3830 sizeof(xmlRelaxNGDefinePtr *));
3831 if (list == NULL) {
3832 if (ctxt->error != NULL)
3833 ctxt->error(ctxt->userData,
3834 "Out of memory in choice computation\n");
3835 ctxt->nbErrors++;
3836 return;
3837 }
3838 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003839 /*
3840 * a bit strong but safe
3841 */
3842 if (is_nullable == 0) {
3843 triage = xmlHashCreate(10);
3844 } else {
3845 is_triable = 0;
3846 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003847 cur = def->content;
3848 while (cur != NULL) {
3849 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003850 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3851 is_triable = 0;
3852 } else if (is_triable == 1) {
3853 xmlRelaxNGDefinePtr *tmp;
3854 int res;
3855
3856 tmp = list[i];
3857 while ((*tmp != NULL) && (is_triable == 1)) {
3858 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3859 res = xmlHashAddEntry2(triage,
3860 BAD_CAST "#text", NULL,
3861 (void *)cur);
3862 if (res != 0)
3863 is_triable = -1;
3864 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3865 ((*tmp)->name != NULL)) {
3866 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3867 res = xmlHashAddEntry2(triage,
3868 (*tmp)->name, NULL,
3869 (void *)cur);
3870 else
3871 res = xmlHashAddEntry2(triage,
3872 (*tmp)->name, (*tmp)->ns,
3873 (void *)cur);
3874 if (res != 0)
3875 is_triable = -1;
3876 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3877 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3878 res = xmlHashAddEntry2(triage,
3879 BAD_CAST "#any", NULL,
3880 (void *)cur);
3881 else
3882 res = xmlHashAddEntry2(triage,
3883 BAD_CAST "#any", (*tmp)->ns,
3884 (void *)cur);
3885 if (res != 0)
3886 is_triable = -1;
3887 } else {
3888 is_triable = -1;
3889 }
3890 tmp++;
3891 }
3892 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003893 i++;
3894 cur = cur->next;
3895 }
3896
3897 for (i = 0;i < nbchild;i++) {
3898 if (list[i] == NULL)
3899 continue;
3900 for (j = 0;j < i;j++) {
3901 if (list[j] == NULL)
3902 continue;
3903 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3904 if (ret == 0) {
3905 is_indeterminist = 1;
3906 }
3907 }
3908 }
3909 for (i = 0;i < nbchild;i++) {
3910 if (list[i] != NULL)
3911 xmlFree(list[i]);
3912 }
3913
3914 xmlFree(list);
3915 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003916 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003917 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003918 if (is_triable == 1) {
3919 def->dflags |= IS_TRIABLE;
3920 def->data = triage;
3921 } else if (triage != NULL) {
3922 xmlHashFree(triage, NULL);
3923 }
3924 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003925}
3926
3927/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003928 * xmlRelaxNGCheckGroupAttrs:
3929 * @ctxt: a Relax-NG parser context
3930 * @def: the group definition
3931 *
3932 * Detects violations of rule 7.3
3933 */
3934static void
3935xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3936 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003937 xmlRelaxNGDefinePtr **list;
3938 xmlRelaxNGDefinePtr cur;
3939 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003940
3941 if ((def == NULL) ||
3942 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003943 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003944 return;
3945
Daniel Veillarde063f482003-03-21 16:53:17 +00003946 if (def->dflags & IS_PROCESSED)
3947 return;
3948
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003949 /*
3950 * Don't run that check in case of error. Infinite recursion
3951 * becomes possible.
3952 */
3953 if (ctxt->nbErrors != 0)
3954 return;
3955
Daniel Veillardfd573f12003-03-16 17:52:32 +00003956 cur = def->attrs;
3957 while (cur != NULL) {
3958 nbchild++;
3959 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003960 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003961 cur = def->content;
3962 while (cur != NULL) {
3963 nbchild++;
3964 cur = cur->next;
3965 }
3966
3967 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3968 sizeof(xmlRelaxNGDefinePtr *));
3969 if (list == NULL) {
3970 if (ctxt->error != NULL)
3971 ctxt->error(ctxt->userData,
3972 "Out of memory in group computation\n");
3973 ctxt->nbErrors++;
3974 return;
3975 }
3976 i = 0;
3977 cur = def->attrs;
3978 while (cur != NULL) {
3979 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3980 i++;
3981 cur = cur->next;
3982 }
3983 cur = def->content;
3984 while (cur != NULL) {
3985 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3986 i++;
3987 cur = cur->next;
3988 }
3989
3990 for (i = 0;i < nbchild;i++) {
3991 if (list[i] == NULL)
3992 continue;
3993 for (j = 0;j < i;j++) {
3994 if (list[j] == NULL)
3995 continue;
3996 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3997 if (ret == 0) {
3998 if (ctxt->error != NULL)
3999 ctxt->error(ctxt->userData,
4000 "Attributes conflicts in group\n");
4001 ctxt->nbErrors++;
4002 }
4003 }
4004 }
4005 for (i = 0;i < nbchild;i++) {
4006 if (list[i] != NULL)
4007 xmlFree(list[i]);
4008 }
4009
4010 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004011 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004012}
4013
4014/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004015 * xmlRelaxNGComputeInterleaves:
4016 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004017 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004018 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004019 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004020 * A lot of work for preprocessing interleave definitions
4021 * is potentially needed to get a decent execution speed at runtime
4022 * - trying to get a total order on the element nodes generated
4023 * by the interleaves, order the list of interleave definitions
4024 * following that order.
4025 * - if <text/> is used to handle mixed content, it is better to
4026 * flag this in the define and simplify the runtime checking
4027 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004028 */
4029static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004030xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4031 xmlRelaxNGParserCtxtPtr ctxt,
4032 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004033 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004034
Daniel Veillardfd573f12003-03-16 17:52:32 +00004035 xmlRelaxNGPartitionPtr partitions = NULL;
4036 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4037 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004038 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004039 int nbgroups = 0;
4040 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004041 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004042 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004043
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004044 /*
4045 * Don't run that check in case of error. Infinite recursion
4046 * becomes possible.
4047 */
4048 if (ctxt->nbErrors != 0)
4049 return;
4050
Daniel Veillardfd573f12003-03-16 17:52:32 +00004051#ifdef DEBUG_INTERLEAVE
4052 xmlGenericError(xmlGenericErrorContext,
4053 "xmlRelaxNGComputeInterleaves(%s)\n",
4054 name);
4055#endif
4056 cur = def->content;
4057 while (cur != NULL) {
4058 nbchild++;
4059 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004060 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004061
4062#ifdef DEBUG_INTERLEAVE
4063 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4064#endif
4065 groups = (xmlRelaxNGInterleaveGroupPtr *)
4066 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4067 if (groups == NULL)
4068 goto error;
4069 cur = def->content;
4070 while (cur != NULL) {
4071 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4072 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4073 if (groups[nbgroups] == NULL)
4074 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004075 if (cur->type == XML_RELAXNG_TEXT)
4076 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004077 groups[nbgroups]->rule = cur;
4078 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4079 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4080 nbgroups++;
4081 cur = cur->next;
4082 }
4083#ifdef DEBUG_INTERLEAVE
4084 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4085#endif
4086
4087 /*
4088 * Let's check that all rules makes a partitions according to 7.4
4089 */
4090 partitions = (xmlRelaxNGPartitionPtr)
4091 xmlMalloc(sizeof(xmlRelaxNGPartition));
4092 if (partitions == NULL)
4093 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004094 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004095 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004096 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004097 for (i = 0;i < nbgroups;i++) {
4098 group = groups[i];
4099 for (j = i+1;j < nbgroups;j++) {
4100 if (groups[j] == NULL)
4101 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004102
Daniel Veillardfd573f12003-03-16 17:52:32 +00004103 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4104 groups[j]->defs);
4105 if (ret == 0) {
4106 if (ctxt->error != NULL)
4107 ctxt->error(ctxt->userData,
4108 "Element or text conflicts in interleave\n");
4109 ctxt->nbErrors++;
4110 }
4111 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4112 groups[j]->attrs);
4113 if (ret == 0) {
4114 if (ctxt->error != NULL)
4115 ctxt->error(ctxt->userData,
4116 "Attributes conflicts in interleave\n");
4117 ctxt->nbErrors++;
4118 }
4119 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004120 tmp = group->defs;
4121 if ((tmp != NULL) && (*tmp != NULL)) {
4122 while (*tmp != NULL) {
4123 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4124 res = xmlHashAddEntry2(partitions->triage,
4125 BAD_CAST "#text", NULL,
4126 (void *)(i + 1));
4127 if (res != 0)
4128 is_determinist = -1;
4129 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4130 ((*tmp)->name != NULL)) {
4131 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4132 res = xmlHashAddEntry2(partitions->triage,
4133 (*tmp)->name, NULL,
4134 (void *)(i + 1));
4135 else
4136 res = xmlHashAddEntry2(partitions->triage,
4137 (*tmp)->name, (*tmp)->ns,
4138 (void *)(i + 1));
4139 if (res != 0)
4140 is_determinist = -1;
4141 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4142 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4143 res = xmlHashAddEntry2(partitions->triage,
4144 BAD_CAST "#any", NULL,
4145 (void *)(i + 1));
4146 else
4147 res = xmlHashAddEntry2(partitions->triage,
4148 BAD_CAST "#any", (*tmp)->ns,
4149 (void *)(i + 1));
4150 if ((*tmp)->nameClass != NULL)
4151 is_determinist = 2;
4152 if (res != 0)
4153 is_determinist = -1;
4154 } else {
4155 is_determinist = -1;
4156 }
4157 tmp++;
4158 }
4159 } else {
4160 is_determinist = 0;
4161 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162 }
4163 partitions->groups = groups;
4164
4165 /*
4166 * and save the partition list back in the def
4167 */
4168 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004169 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00004170 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004171 if (is_determinist == 1)
4172 partitions->flags = IS_DETERMINIST;
4173 if (is_determinist == 2)
4174 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004175 return;
4176
4177error:
4178 if (ctxt->error != NULL)
4179 ctxt->error(ctxt->userData,
4180 "Out of memory in interleave computation\n");
4181 ctxt->nbErrors++;
4182 if (groups != NULL) {
4183 for (i = 0;i < nbgroups;i++)
4184 if (groups[i] != NULL) {
4185 if (groups[i]->defs != NULL)
4186 xmlFree(groups[i]->defs);
4187 xmlFree(groups[i]);
4188 }
4189 xmlFree(groups);
4190 }
4191 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004192}
4193
4194/**
4195 * xmlRelaxNGParseInterleave:
4196 * @ctxt: a Relax-NG parser context
4197 * @node: the data node.
4198 *
4199 * parse the content of a RelaxNG interleave node.
4200 *
4201 * Returns the definition pointer or NULL in case of error
4202 */
4203static xmlRelaxNGDefinePtr
4204xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4205 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004206 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004207 xmlNodePtr child;
4208
Daniel Veillardfd573f12003-03-16 17:52:32 +00004209 def = xmlRelaxNGNewDefine(ctxt, node);
4210 if (def == NULL) {
4211 return(NULL);
4212 }
4213 def->type = XML_RELAXNG_INTERLEAVE;
4214
4215 if (ctxt->interleaves == NULL)
4216 ctxt->interleaves = xmlHashCreate(10);
4217 if (ctxt->interleaves == NULL) {
4218 if (ctxt->error != NULL)
4219 ctxt->error(ctxt->userData,
4220 "Failed to create interleaves hash table\n");
4221 ctxt->nbErrors++;
4222 } else {
4223 char name[32];
4224
4225 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4226 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4227 if (ctxt->error != NULL)
4228 ctxt->error(ctxt->userData,
4229 "Failed to add %s to hash table\n", name);
4230 ctxt->nbErrors++;
4231 }
4232 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004233 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004234 if (child == NULL) {
4235 if (ctxt->error != NULL)
4236 ctxt->error(ctxt->userData, "Element interleave is empty\n");
4237 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004238 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004239 while (child != NULL) {
4240 if (IS_RELAXNG(child, "element")) {
4241 cur = xmlRelaxNGParseElement(ctxt, child);
4242 } else {
4243 cur = xmlRelaxNGParsePattern(ctxt, child);
4244 }
4245 if (cur != NULL) {
4246 cur->parent = def;
4247 if (last == NULL) {
4248 def->content = last = cur;
4249 } else {
4250 last->next = cur;
4251 last = cur;
4252 }
4253 }
4254 child = child->next;
4255 }
4256
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004257 return(def);
4258}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004259
4260/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004261 * xmlRelaxNGParseInclude:
4262 * @ctxt: a Relax-NG parser context
4263 * @node: the include node
4264 *
4265 * Integrate the content of an include node in the current grammar
4266 *
4267 * Returns 0 in case of success or -1 in case of error
4268 */
4269static int
4270xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4271 xmlRelaxNGIncludePtr incl;
4272 xmlNodePtr root;
4273 int ret = 0, tmp;
4274
4275 incl = node->_private;
4276 if (incl == NULL) {
4277 if (ctxt->error != NULL)
4278 ctxt->error(ctxt->userData,
4279 "Include node has no data\n");
4280 ctxt->nbErrors++;
4281 return(-1);
4282 }
4283 root = xmlDocGetRootElement(incl->doc);
4284 if (root == NULL) {
4285 if (ctxt->error != NULL)
4286 ctxt->error(ctxt->userData,
4287 "Include document is empty\n");
4288 ctxt->nbErrors++;
4289 return(-1);
4290 }
4291 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4292 if (ctxt->error != NULL)
4293 ctxt->error(ctxt->userData,
4294 "Include document root is not a grammar\n");
4295 ctxt->nbErrors++;
4296 return(-1);
4297 }
4298
4299 /*
4300 * Merge the definition from both the include and the internal list
4301 */
4302 if (root->children != NULL) {
4303 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4304 if (tmp != 0)
4305 ret = -1;
4306 }
4307 if (node->children != NULL) {
4308 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4309 if (tmp != 0)
4310 ret = -1;
4311 }
4312 return(ret);
4313}
4314
4315/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004316 * xmlRelaxNGParseDefine:
4317 * @ctxt: a Relax-NG parser context
4318 * @node: the define node
4319 *
4320 * parse the content of a RelaxNG define element node.
4321 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004322 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004323 */
4324static int
4325xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4326 xmlChar *name;
4327 int ret = 0, tmp;
4328 xmlRelaxNGDefinePtr def;
4329 const xmlChar *olddefine;
4330
4331 name = xmlGetProp(node, BAD_CAST "name");
4332 if (name == NULL) {
4333 if (ctxt->error != NULL)
4334 ctxt->error(ctxt->userData,
4335 "define has no name\n");
4336 ctxt->nbErrors++;
4337 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004338 xmlRelaxNGNormExtSpace(name);
4339 if (xmlValidateNCName(name, 0)) {
4340 if (ctxt->error != NULL)
4341 ctxt->error(ctxt->userData,
4342 "define name '%s' is not an NCName\n",
4343 name);
4344 ctxt->nbErrors++;
4345 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004346 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004347 if (def == NULL) {
4348 xmlFree(name);
4349 return(-1);
4350 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004351 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004352 def->name = name;
4353 if (node->children == NULL) {
4354 if (ctxt->error != NULL)
4355 ctxt->error(ctxt->userData,
4356 "define has no children\n");
4357 ctxt->nbErrors++;
4358 } else {
4359 olddefine = ctxt->define;
4360 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00004361 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004362 ctxt->define = olddefine;
4363 }
4364 if (ctxt->grammar->defs == NULL)
4365 ctxt->grammar->defs = xmlHashCreate(10);
4366 if (ctxt->grammar->defs == NULL) {
4367 if (ctxt->error != NULL)
4368 ctxt->error(ctxt->userData,
4369 "Could not create definition hash\n");
4370 ctxt->nbErrors++;
4371 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004372 } else {
4373 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4374 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00004375 xmlRelaxNGDefinePtr prev;
4376
4377 prev = xmlHashLookup(ctxt->grammar->defs, name);
4378 if (prev == NULL) {
4379 if (ctxt->error != NULL)
4380 ctxt->error(ctxt->userData,
4381 "Internal error on define aggregation of %s\n",
4382 name);
4383 ctxt->nbErrors++;
4384 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00004385 } else {
4386 while (prev->nextHash != NULL)
4387 prev = prev->nextHash;
4388 prev->nextHash = def;
4389 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004390 }
4391 }
4392 }
4393 return(ret);
4394}
4395
4396/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004397 * xmlRelaxNGProcessExternalRef:
4398 * @ctxt: the parser context
4399 * @node: the externlRef node
4400 *
4401 * Process and compile an externlRef node
4402 *
4403 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4404 */
4405static xmlRelaxNGDefinePtr
4406xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4407 xmlRelaxNGDocumentPtr docu;
4408 xmlNodePtr root, tmp;
4409 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004410 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004411 xmlRelaxNGDefinePtr def;
4412
4413 docu = node->_private;
4414 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004415 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004416 if (def == NULL)
4417 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004418 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004419
4420 if (docu->content == NULL) {
4421 /*
4422 * Then do the parsing for good
4423 */
4424 root = xmlDocGetRootElement(docu->doc);
4425 if (root == NULL) {
4426 if (ctxt->error != NULL)
4427 ctxt->error(ctxt->userData,
4428 "xmlRelaxNGParse: %s is empty\n",
4429 ctxt->URL);
4430 ctxt->nbErrors++;
4431 return (NULL);
4432 }
4433 /*
4434 * ns transmission rules
4435 */
4436 ns = xmlGetProp(root, BAD_CAST "ns");
4437 if (ns == NULL) {
4438 tmp = node;
4439 while ((tmp != NULL) &&
4440 (tmp->type == XML_ELEMENT_NODE)) {
4441 ns = xmlGetProp(tmp, BAD_CAST "ns");
4442 if (ns != NULL) {
4443 break;
4444 }
4445 tmp = tmp->parent;
4446 }
4447 if (ns != NULL) {
4448 xmlSetProp(root, BAD_CAST "ns", ns);
4449 newNs = 1;
4450 xmlFree(ns);
4451 }
4452 } else {
4453 xmlFree(ns);
4454 }
4455
4456 /*
4457 * Parsing to get a precompiled schemas.
4458 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004459 oldflags = ctxt->flags;
4460 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004461 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004462 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004463 if ((docu->schema != NULL) &&
4464 (docu->schema->topgrammar != NULL)) {
4465 docu->content = docu->schema->topgrammar->start;
4466 }
4467
4468 /*
4469 * the externalRef may be reused in a different ns context
4470 */
4471 if (newNs == 1) {
4472 xmlUnsetProp(root, BAD_CAST "ns");
4473 }
4474 }
4475 def->content = docu->content;
4476 } else {
4477 def = NULL;
4478 }
4479 return(def);
4480}
4481
4482/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004483 * xmlRelaxNGParsePattern:
4484 * @ctxt: a Relax-NG parser context
4485 * @node: the pattern node.
4486 *
4487 * parse the content of a RelaxNG pattern node.
4488 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004489 * Returns the definition pointer or NULL in case of error or if no
4490 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004491 */
4492static xmlRelaxNGDefinePtr
4493xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4494 xmlRelaxNGDefinePtr def = NULL;
4495
Daniel Veillardd2298792003-02-14 16:54:11 +00004496 if (node == NULL) {
4497 return(NULL);
4498 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004499 if (IS_RELAXNG(node, "element")) {
4500 def = xmlRelaxNGParseElement(ctxt, node);
4501 } else if (IS_RELAXNG(node, "attribute")) {
4502 def = xmlRelaxNGParseAttribute(ctxt, node);
4503 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004504 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004505 if (def == NULL)
4506 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004507 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004508 if (node->children != NULL) {
4509 if (ctxt->error != NULL)
4510 ctxt->error(ctxt->userData, "empty: had a child node\n");
4511 ctxt->nbErrors++;
4512 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004513 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004514 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004515 if (def == NULL)
4516 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004517 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004518 if (node->children != NULL) {
4519 if (ctxt->error != NULL)
4520 ctxt->error(ctxt->userData, "text: had a child node\n");
4521 ctxt->nbErrors++;
4522 }
4523 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004524 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004525 if (def == NULL)
4526 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004527 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004528 if (node->children == NULL) {
4529 if (ctxt->error != NULL)
4530 ctxt->error(ctxt->userData,
4531 "Element %s is empty\n", node->name);
4532 ctxt->nbErrors++;
4533 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004534 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004535 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004536 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004537 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004538 if (def == NULL)
4539 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004540 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004541 if (node->children == NULL) {
4542 if (ctxt->error != NULL)
4543 ctxt->error(ctxt->userData,
4544 "Element %s is empty\n", node->name);
4545 ctxt->nbErrors++;
4546 } else {
4547 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4548 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004549 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004550 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004551 if (def == NULL)
4552 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004553 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004554 if (node->children == NULL) {
4555 if (ctxt->error != NULL)
4556 ctxt->error(ctxt->userData,
4557 "Element %s is empty\n", node->name);
4558 ctxt->nbErrors++;
4559 } else {
4560 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4561 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004562 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004563 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004564 if (def == NULL)
4565 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004566 def->type = XML_RELAXNG_CHOICE;
4567 if (node->children == NULL) {
4568 if (ctxt->error != NULL)
4569 ctxt->error(ctxt->userData,
4570 "Element %s is empty\n", node->name);
4571 ctxt->nbErrors++;
4572 } else {
4573 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4574 }
4575 } else if (IS_RELAXNG(node, "group")) {
4576 def = xmlRelaxNGNewDefine(ctxt, node);
4577 if (def == NULL)
4578 return(NULL);
4579 def->type = XML_RELAXNG_GROUP;
4580 if (node->children == NULL) {
4581 if (ctxt->error != NULL)
4582 ctxt->error(ctxt->userData,
4583 "Element %s is empty\n", node->name);
4584 ctxt->nbErrors++;
4585 } else {
4586 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4587 }
4588 } else if (IS_RELAXNG(node, "ref")) {
4589 def = xmlRelaxNGNewDefine(ctxt, node);
4590 if (def == NULL)
4591 return(NULL);
4592 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004593 def->name = xmlGetProp(node, BAD_CAST "name");
4594 if (def->name == NULL) {
4595 if (ctxt->error != NULL)
4596 ctxt->error(ctxt->userData,
4597 "ref has no name\n");
4598 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004599 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004600 xmlRelaxNGNormExtSpace(def->name);
4601 if (xmlValidateNCName(def->name, 0)) {
4602 if (ctxt->error != NULL)
4603 ctxt->error(ctxt->userData,
4604 "ref name '%s' is not an NCName\n",
4605 def->name);
4606 ctxt->nbErrors++;
4607 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004608 }
4609 if (node->children != NULL) {
4610 if (ctxt->error != NULL)
4611 ctxt->error(ctxt->userData,
4612 "ref is not empty\n");
4613 ctxt->nbErrors++;
4614 }
4615 if (ctxt->grammar->refs == NULL)
4616 ctxt->grammar->refs = xmlHashCreate(10);
4617 if (ctxt->grammar->refs == NULL) {
4618 if (ctxt->error != NULL)
4619 ctxt->error(ctxt->userData,
4620 "Could not create references hash\n");
4621 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004622 def = NULL;
4623 } else {
4624 int tmp;
4625
4626 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4627 if (tmp < 0) {
4628 xmlRelaxNGDefinePtr prev;
4629
4630 prev = (xmlRelaxNGDefinePtr)
4631 xmlHashLookup(ctxt->grammar->refs, def->name);
4632 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004633 if (def->name != NULL) {
4634 if (ctxt->error != NULL)
4635 ctxt->error(ctxt->userData,
4636 "Error refs definitions '%s'\n",
4637 def->name);
4638 } else {
4639 if (ctxt->error != NULL)
4640 ctxt->error(ctxt->userData,
4641 "Error refs definitions\n");
4642 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004643 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004644 def = NULL;
4645 } else {
4646 def->nextHash = prev->nextHash;
4647 prev->nextHash = def;
4648 }
4649 }
4650 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004651 } else if (IS_RELAXNG(node, "data")) {
4652 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004653 } else if (IS_RELAXNG(node, "value")) {
4654 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004655 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004656 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004657 if (def == NULL)
4658 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004659 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004660 if (node->children == NULL) {
4661 if (ctxt->error != NULL)
4662 ctxt->error(ctxt->userData,
4663 "Element %s is empty\n", node->name);
4664 ctxt->nbErrors++;
4665 } else {
4666 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4667 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004668 } else if (IS_RELAXNG(node, "interleave")) {
4669 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004670 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004671 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004672 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004673 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004674 if (def == NULL)
4675 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004676 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004677 if (node->children != NULL) {
4678 if (ctxt->error != NULL)
4679 ctxt->error(ctxt->userData,
4680 "xmlRelaxNGParse: notAllowed element is not empty\n");
4681 ctxt->nbErrors++;
4682 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004683 } else if (IS_RELAXNG(node, "grammar")) {
4684 xmlRelaxNGGrammarPtr grammar, old;
4685 xmlRelaxNGGrammarPtr oldparent;
4686
Daniel Veillardc482e262003-02-26 14:48:48 +00004687#ifdef DEBUG_GRAMMAR
4688 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4689#endif
4690
Daniel Veillard419a7682003-02-03 23:22:49 +00004691 oldparent = ctxt->parentgrammar;
4692 old = ctxt->grammar;
4693 ctxt->parentgrammar = old;
4694 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4695 if (old != NULL) {
4696 ctxt->grammar = old;
4697 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004698#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004699 if (grammar != NULL) {
4700 grammar->next = old->next;
4701 old->next = grammar;
4702 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004703#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004704 }
4705 if (grammar != NULL)
4706 def = grammar->start;
4707 else
4708 def = NULL;
4709 } else if (IS_RELAXNG(node, "parentRef")) {
4710 if (ctxt->parentgrammar == NULL) {
4711 if (ctxt->error != NULL)
4712 ctxt->error(ctxt->userData,
4713 "Use of parentRef without a parent grammar\n");
4714 ctxt->nbErrors++;
4715 return(NULL);
4716 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004717 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004718 if (def == NULL)
4719 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004720 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004721 def->name = xmlGetProp(node, BAD_CAST "name");
4722 if (def->name == NULL) {
4723 if (ctxt->error != NULL)
4724 ctxt->error(ctxt->userData,
4725 "parentRef has no name\n");
4726 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004727 } else {
4728 xmlRelaxNGNormExtSpace(def->name);
4729 if (xmlValidateNCName(def->name, 0)) {
4730 if (ctxt->error != NULL)
4731 ctxt->error(ctxt->userData,
4732 "parentRef name '%s' is not an NCName\n",
4733 def->name);
4734 ctxt->nbErrors++;
4735 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004736 }
4737 if (node->children != NULL) {
4738 if (ctxt->error != NULL)
4739 ctxt->error(ctxt->userData,
4740 "parentRef is not empty\n");
4741 ctxt->nbErrors++;
4742 }
4743 if (ctxt->parentgrammar->refs == NULL)
4744 ctxt->parentgrammar->refs = xmlHashCreate(10);
4745 if (ctxt->parentgrammar->refs == NULL) {
4746 if (ctxt->error != NULL)
4747 ctxt->error(ctxt->userData,
4748 "Could not create references hash\n");
4749 ctxt->nbErrors++;
4750 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004751 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004752 int tmp;
4753
4754 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4755 if (tmp < 0) {
4756 xmlRelaxNGDefinePtr prev;
4757
4758 prev = (xmlRelaxNGDefinePtr)
4759 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4760 if (prev == NULL) {
4761 if (ctxt->error != NULL)
4762 ctxt->error(ctxt->userData,
4763 "Internal error parentRef definitions '%s'\n",
4764 def->name);
4765 ctxt->nbErrors++;
4766 def = NULL;
4767 } else {
4768 def->nextHash = prev->nextHash;
4769 prev->nextHash = def;
4770 }
4771 }
4772 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004773 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004774 if (node->children == NULL) {
4775 if (ctxt->error != NULL)
4776 ctxt->error(ctxt->userData,
4777 "Mixed is empty\n");
4778 ctxt->nbErrors++;
4779 def = NULL;
4780 } else {
4781 def = xmlRelaxNGParseInterleave(ctxt, node);
4782 if (def != NULL) {
4783 xmlRelaxNGDefinePtr tmp;
4784
4785 if ((def->content != NULL) && (def->content->next != NULL)) {
4786 tmp = xmlRelaxNGNewDefine(ctxt, node);
4787 if (tmp != NULL) {
4788 tmp->type = XML_RELAXNG_GROUP;
4789 tmp->content = def->content;
4790 def->content = tmp;
4791 }
4792 }
4793
4794 tmp = xmlRelaxNGNewDefine(ctxt, node);
4795 if (tmp == NULL)
4796 return(def);
4797 tmp->type = XML_RELAXNG_TEXT;
4798 tmp->next = def->content;
4799 def->content = tmp;
4800 }
4801 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004802 } else {
4803 if (ctxt->error != NULL)
4804 ctxt->error(ctxt->userData,
4805 "Unexpected node %s is not a pattern\n",
4806 node->name);
4807 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004808 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004809 }
4810 return(def);
4811}
4812
4813/**
4814 * xmlRelaxNGParseAttribute:
4815 * @ctxt: a Relax-NG parser context
4816 * @node: the element node
4817 *
4818 * parse the content of a RelaxNG attribute node.
4819 *
4820 * Returns the definition pointer or NULL in case of error.
4821 */
4822static xmlRelaxNGDefinePtr
4823xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004824 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004825 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004826 int old_flags;
4827
Daniel Veillardfd573f12003-03-16 17:52:32 +00004828 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004829 if (ret == NULL)
4830 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004831 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004832 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004833 child = node->children;
4834 if (child == NULL) {
4835 if (ctxt->error != NULL)
4836 ctxt->error(ctxt->userData,
4837 "xmlRelaxNGParseattribute: attribute has no children\n");
4838 ctxt->nbErrors++;
4839 return(ret);
4840 }
4841 old_flags = ctxt->flags;
4842 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004843 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4844 if (cur != NULL)
4845 child = child->next;
4846
Daniel Veillardd2298792003-02-14 16:54:11 +00004847 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004848 cur = xmlRelaxNGParsePattern(ctxt, child);
4849 if (cur != NULL) {
4850 switch (cur->type) {
4851 case XML_RELAXNG_EMPTY:
4852 case XML_RELAXNG_NOT_ALLOWED:
4853 case XML_RELAXNG_TEXT:
4854 case XML_RELAXNG_ELEMENT:
4855 case XML_RELAXNG_DATATYPE:
4856 case XML_RELAXNG_VALUE:
4857 case XML_RELAXNG_LIST:
4858 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004859 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004860 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004861 case XML_RELAXNG_DEF:
4862 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004863 case XML_RELAXNG_ZEROORMORE:
4864 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004865 case XML_RELAXNG_CHOICE:
4866 case XML_RELAXNG_GROUP:
4867 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004868 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004869 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004870 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004871 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004872 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004873 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004874 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004875 if (ctxt->error != NULL)
4876 ctxt->error(ctxt->userData,
4877 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004878 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004879 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004880 case XML_RELAXNG_NOOP:
4881 TODO
4882 if (ctxt->error != NULL)
4883 ctxt->error(ctxt->userData,
4884 "Internal error, noop found\n");
4885 ctxt->nbErrors++;
4886 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004887 }
4888 }
4889 child = child->next;
4890 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004891 if (child != NULL) {
4892 if (ctxt->error != NULL)
4893 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4894 ctxt->nbErrors++;
4895 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004896 ctxt->flags = old_flags;
4897 return(ret);
4898}
4899
4900/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004901 * xmlRelaxNGParseExceptNameClass:
4902 * @ctxt: a Relax-NG parser context
4903 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004904 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004905 *
4906 * parse the content of a RelaxNG nameClass node.
4907 *
4908 * Returns the definition pointer or NULL in case of error.
4909 */
4910static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004911xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4912 xmlNodePtr node, int attr) {
4913 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4914 xmlNodePtr child;
4915
Daniel Veillardd2298792003-02-14 16:54:11 +00004916 if (!IS_RELAXNG(node, "except")) {
4917 if (ctxt->error != NULL)
4918 ctxt->error(ctxt->userData,
4919 "Expecting an except node\n");
4920 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004921 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004922 }
4923 if (node->next != NULL) {
4924 if (ctxt->error != NULL)
4925 ctxt->error(ctxt->userData,
4926 "exceptNameClass allows only a single except node\n");
4927 ctxt->nbErrors++;
4928 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004929 if (node->children == NULL) {
4930 if (ctxt->error != NULL)
4931 ctxt->error(ctxt->userData,
4932 "except has no content\n");
4933 ctxt->nbErrors++;
4934 return(NULL);
4935 }
4936
Daniel Veillardfd573f12003-03-16 17:52:32 +00004937 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004938 if (ret == NULL)
4939 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004940 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004941 child = node->children;
4942 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004943 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004944 if (cur == NULL)
4945 break;
4946 if (attr)
4947 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004948 else
4949 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004950
Daniel Veillard419a7682003-02-03 23:22:49 +00004951 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004952 if (last == NULL) {
4953 ret->content = cur;
4954 } else {
4955 last->next = cur;
4956 }
4957 last = cur;
4958 }
4959 child = child->next;
4960 }
4961
4962 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004963}
4964
4965/**
4966 * xmlRelaxNGParseNameClass:
4967 * @ctxt: a Relax-NG parser context
4968 * @node: the nameClass node
4969 * @def: the current definition
4970 *
4971 * parse the content of a RelaxNG nameClass node.
4972 *
4973 * Returns the definition pointer or NULL in case of error.
4974 */
4975static xmlRelaxNGDefinePtr
4976xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4977 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004978 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004979 xmlChar *val;
4980
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004981 ret = def;
4982 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4983 (IS_RELAXNG(node, "nsName"))) {
4984 if ((def->type != XML_RELAXNG_ELEMENT) &&
4985 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004986 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004987 if (ret == NULL)
4988 return(NULL);
4989 ret->parent = def;
4990 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4991 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004992 else
4993 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004994 }
4995 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004996 if (IS_RELAXNG(node, "name")) {
4997 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004998 xmlRelaxNGNormExtSpace(val);
4999 if (xmlValidateNCName(val, 0)) {
5000 if (ctxt->error != NULL) {
5001 if (node->parent != NULL)
5002 ctxt->error(ctxt->userData,
5003 "Element %s name '%s' is not an NCName\n",
5004 node->parent->name, val);
5005 else
5006 ctxt->error(ctxt->userData,
5007 "name '%s' is not an NCName\n",
5008 val);
5009 }
5010 ctxt->nbErrors++;
5011 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005012 ret->name = val;
5013 val = xmlGetProp(node, BAD_CAST "ns");
5014 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00005015 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5016 (val != NULL) &&
5017 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5018 ctxt->error(ctxt->userData,
5019 "Attribute with namespace '%s' is not allowed\n",
5020 val);
5021 ctxt->nbErrors++;
5022 }
5023 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5024 (val != NULL) &&
5025 (val[0] == 0) &&
5026 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5027 ctxt->error(ctxt->userData,
5028 "Attribute with QName 'xmlns' is not allowed\n",
5029 val);
5030 ctxt->nbErrors++;
5031 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005032 } else if (IS_RELAXNG(node, "anyName")) {
5033 ret->name = NULL;
5034 ret->ns = NULL;
5035 if (node->children != NULL) {
5036 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005037 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5038 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005039 }
5040 } else if (IS_RELAXNG(node, "nsName")) {
5041 ret->name = NULL;
5042 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5043 if (ret->ns == NULL) {
5044 if (ctxt->error != NULL)
5045 ctxt->error(ctxt->userData,
5046 "nsName has no ns attribute\n");
5047 ctxt->nbErrors++;
5048 }
Daniel Veillard416589a2003-02-17 17:25:42 +00005049 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5050 (ret->ns != NULL) &&
5051 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5052 ctxt->error(ctxt->userData,
5053 "Attribute with namespace '%s' is not allowed\n",
5054 ret->ns);
5055 ctxt->nbErrors++;
5056 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005057 if (node->children != NULL) {
5058 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005059 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5060 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005061 }
5062 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005063 xmlNodePtr child;
5064 xmlRelaxNGDefinePtr last = NULL;
5065
5066 ret = xmlRelaxNGNewDefine(ctxt, node);
5067 if (ret == NULL)
5068 return(NULL);
5069 ret->parent = def;
5070 ret->type = XML_RELAXNG_CHOICE;
5071
Daniel Veillardd2298792003-02-14 16:54:11 +00005072 if (node->children == NULL) {
5073 if (ctxt->error != NULL)
5074 ctxt->error(ctxt->userData,
5075 "Element choice is empty\n");
5076 ctxt->nbErrors++;
5077 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005078
5079 child = node->children;
5080 while (child != NULL) {
5081 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5082 if (tmp != NULL) {
5083 if (last == NULL) {
5084 last = ret->nameClass = tmp;
5085 } else {
5086 last->next = tmp;
5087 last = tmp;
5088 }
5089 }
5090 child = child->next;
5091 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005092 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005093 } else {
5094 if (ctxt->error != NULL)
5095 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00005096 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005097 node->name);
5098 ctxt->nbErrors++;
5099 return(NULL);
5100 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005101 if (ret != def) {
5102 if (def->nameClass == NULL) {
5103 def->nameClass = ret;
5104 } else {
5105 tmp = def->nameClass;
5106 while (tmp->next != NULL) {
5107 tmp = tmp->next;
5108 }
5109 tmp->next = ret;
5110 }
5111 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005112 return(ret);
5113}
5114
5115/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005116 * xmlRelaxNGParseElement:
5117 * @ctxt: a Relax-NG parser context
5118 * @node: the element node
5119 *
5120 * parse the content of a RelaxNG element node.
5121 *
5122 * Returns the definition pointer or NULL in case of error.
5123 */
5124static xmlRelaxNGDefinePtr
5125xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5126 xmlRelaxNGDefinePtr ret, cur, last;
5127 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005128 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005129
Daniel Veillardfd573f12003-03-16 17:52:32 +00005130 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005131 if (ret == NULL)
5132 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005133 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005134 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005135 child = node->children;
5136 if (child == NULL) {
5137 if (ctxt->error != NULL)
5138 ctxt->error(ctxt->userData,
5139 "xmlRelaxNGParseElement: element has no children\n");
5140 ctxt->nbErrors++;
5141 return(ret);
5142 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005143 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5144 if (cur != NULL)
5145 child = child->next;
5146
Daniel Veillard6eadf632003-01-23 18:29:16 +00005147 if (child == NULL) {
5148 if (ctxt->error != NULL)
5149 ctxt->error(ctxt->userData,
5150 "xmlRelaxNGParseElement: element has no content\n");
5151 ctxt->nbErrors++;
5152 return(ret);
5153 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005154 olddefine = ctxt->define;
5155 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005156 last = NULL;
5157 while (child != NULL) {
5158 cur = xmlRelaxNGParsePattern(ctxt, child);
5159 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005160 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005161 switch (cur->type) {
5162 case XML_RELAXNG_EMPTY:
5163 case XML_RELAXNG_NOT_ALLOWED:
5164 case XML_RELAXNG_TEXT:
5165 case XML_RELAXNG_ELEMENT:
5166 case XML_RELAXNG_DATATYPE:
5167 case XML_RELAXNG_VALUE:
5168 case XML_RELAXNG_LIST:
5169 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00005170 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005171 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005172 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005173 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005174 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005175 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005176 case XML_RELAXNG_CHOICE:
5177 case XML_RELAXNG_GROUP:
5178 case XML_RELAXNG_INTERLEAVE:
5179 if (last == NULL) {
5180 ret->content = last = cur;
5181 } else {
5182 if ((last->type == XML_RELAXNG_ELEMENT) &&
5183 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005184 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005185 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005186 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005187 ret->content->content = last;
5188 } else {
5189 ret->content = last;
5190 }
5191 }
5192 last->next = cur;
5193 last = cur;
5194 }
5195 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005196 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardce192eb2003-04-16 15:58:05 +00005197 /* HERE !!! */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005198 cur->next = ret->attrs;
5199 ret->attrs = cur;
5200 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005201 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00005202 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00005203 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005204 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005205 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005206 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00005207 case XML_RELAXNG_NOOP:
5208 TODO
5209 if (ctxt->error != NULL)
5210 ctxt->error(ctxt->userData,
5211 "Internal error, noop found\n");
5212 ctxt->nbErrors++;
5213 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005214 }
5215 }
5216 child = child->next;
5217 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005218 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005219 return(ret);
5220}
5221
5222/**
5223 * xmlRelaxNGParsePatterns:
5224 * @ctxt: a Relax-NG parser context
5225 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005226 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005227 *
5228 * parse the content of a RelaxNG start node.
5229 *
5230 * Returns the definition pointer or NULL in case of error.
5231 */
5232static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005233xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5234 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005235 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005236
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005237 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005238 while (nodes != NULL) {
5239 if (IS_RELAXNG(nodes, "element")) {
5240 cur = xmlRelaxNGParseElement(ctxt, nodes);
5241 if (def == NULL) {
5242 def = last = cur;
5243 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00005244 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5245 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005246 def = xmlRelaxNGNewDefine(ctxt, nodes);
5247 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005248 def->content = last;
5249 }
5250 last->next = cur;
5251 last = cur;
5252 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005253 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005254 } else {
5255 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00005256 if (cur != NULL) {
5257 if (def == NULL) {
5258 def = last = cur;
5259 } else {
5260 last->next = cur;
5261 last = cur;
5262 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005263 }
5264 }
5265 nodes = nodes->next;
5266 }
5267 return(def);
5268}
5269
5270/**
5271 * xmlRelaxNGParseStart:
5272 * @ctxt: a Relax-NG parser context
5273 * @nodes: start children nodes
5274 *
5275 * parse the content of a RelaxNG start node.
5276 *
5277 * Returns 0 in case of success, -1 in case of error
5278 */
5279static int
5280xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5281 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005282 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005283
Daniel Veillardd2298792003-02-14 16:54:11 +00005284 if (nodes == NULL) {
5285 if (ctxt->error != NULL)
5286 ctxt->error(ctxt->userData,
5287 "start has no children\n");
5288 ctxt->nbErrors++;
5289 return(-1);
5290 }
5291 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005292 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005293 if (def == NULL)
5294 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005295 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00005296 if (nodes->children != NULL) {
5297 if (ctxt->error != NULL)
5298 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005299 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005300 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005301 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005302 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005303 if (def == NULL)
5304 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005305 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00005306 if (nodes->children != NULL) {
5307 if (ctxt->error != NULL)
5308 ctxt->error(ctxt->userData,
5309 "element notAllowed is not empty\n");
5310 ctxt->nbErrors++;
5311 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005312 } else {
5313 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005314 }
5315 if (ctxt->grammar->start != NULL) {
5316 last = ctxt->grammar->start;
5317 while (last->next != NULL)
5318 last = last->next;
5319 last->next = def;
5320 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005321 ctxt->grammar->start = def;
5322 }
5323 nodes = nodes->next;
5324 if (nodes != NULL) {
5325 if (ctxt->error != NULL)
5326 ctxt->error(ctxt->userData,
5327 "start more than one children\n");
5328 ctxt->nbErrors++;
5329 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005330 }
5331 return(ret);
5332}
5333
5334/**
5335 * xmlRelaxNGParseGrammarContent:
5336 * @ctxt: a Relax-NG parser context
5337 * @nodes: grammar children nodes
5338 *
5339 * parse the content of a RelaxNG grammar node.
5340 *
5341 * Returns 0 in case of success, -1 in case of error
5342 */
5343static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005344xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005345{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005346 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005347
5348 if (nodes == NULL) {
5349 if (ctxt->error != NULL)
5350 ctxt->error(ctxt->userData,
5351 "grammar has no children\n");
5352 ctxt->nbErrors++;
5353 return(-1);
5354 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005355 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005356 if (IS_RELAXNG(nodes, "start")) {
5357 if (nodes->children == NULL) {
5358 if (ctxt->error != NULL)
5359 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00005360 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005361 ctxt->nbErrors++;
5362 } else {
5363 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5364 if (tmp != 0)
5365 ret = -1;
5366 }
5367 } else if (IS_RELAXNG(nodes, "define")) {
5368 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5369 if (tmp != 0)
5370 ret = -1;
5371 } else if (IS_RELAXNG(nodes, "include")) {
5372 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5373 if (tmp != 0)
5374 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005375 } else {
5376 if (ctxt->error != NULL)
5377 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005378 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005379 ctxt->nbErrors++;
5380 ret = -1;
5381 }
5382 nodes = nodes->next;
5383 }
5384 return (ret);
5385}
5386
5387/**
5388 * xmlRelaxNGCheckReference:
5389 * @ref: the ref
5390 * @ctxt: a Relax-NG parser context
5391 * @name: the name associated to the defines
5392 *
5393 * Applies the 4.17. combine attribute rule for all the define
5394 * element of a given grammar using the same name.
5395 */
5396static void
5397xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5398 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5399 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005400 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005401
5402 grammar = ctxt->grammar;
5403 if (grammar == NULL) {
5404 if (ctxt->error != NULL)
5405 ctxt->error(ctxt->userData,
5406 "Internal error: no grammar in CheckReference %s\n",
5407 name);
5408 ctxt->nbErrors++;
5409 return;
5410 }
5411 if (ref->content != NULL) {
5412 if (ctxt->error != NULL)
5413 ctxt->error(ctxt->userData,
5414 "Internal error: reference has content in CheckReference %s\n",
5415 name);
5416 ctxt->nbErrors++;
5417 return;
5418 }
5419 if (grammar->defs != NULL) {
5420 def = xmlHashLookup(grammar->defs, name);
5421 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005422 cur = ref;
5423 while (cur != NULL) {
5424 cur->content = def;
5425 cur = cur->nextHash;
5426 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005427 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005428 if (ctxt->error != NULL)
5429 ctxt->error(ctxt->userData,
5430 "Reference %s has no matching definition\n",
5431 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005432 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005433 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005434 } else {
5435 if (ctxt->error != NULL)
5436 ctxt->error(ctxt->userData,
5437 "Reference %s has no matching definition\n",
5438 name);
5439 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005440 }
5441 /*
5442 * TODO: make a closure and verify there is no loop !
5443 */
5444}
5445
5446/**
5447 * xmlRelaxNGCheckCombine:
5448 * @define: the define(s) list
5449 * @ctxt: a Relax-NG parser context
5450 * @name: the name associated to the defines
5451 *
5452 * Applies the 4.17. combine attribute rule for all the define
5453 * element of a given grammar using the same name.
5454 */
5455static void
5456xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5457 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5458 xmlChar *combine;
5459 int choiceOrInterleave = -1;
5460 int missing = 0;
5461 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5462
5463 if (define->nextHash == NULL)
5464 return;
5465 cur = define;
5466 while (cur != NULL) {
5467 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5468 if (combine != NULL) {
5469 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5470 if (choiceOrInterleave == -1)
5471 choiceOrInterleave = 1;
5472 else if (choiceOrInterleave == 0) {
5473 if (ctxt->error != NULL)
5474 ctxt->error(ctxt->userData,
5475 "Defines for %s use both 'choice' and 'interleave'\n",
5476 name);
5477 ctxt->nbErrors++;
5478 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005479 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005480 if (choiceOrInterleave == -1)
5481 choiceOrInterleave = 0;
5482 else if (choiceOrInterleave == 1) {
5483 if (ctxt->error != NULL)
5484 ctxt->error(ctxt->userData,
5485 "Defines for %s use both 'choice' and 'interleave'\n",
5486 name);
5487 ctxt->nbErrors++;
5488 }
5489 } else {
5490 if (ctxt->error != NULL)
5491 ctxt->error(ctxt->userData,
5492 "Defines for %s use unknown combine value '%s''\n",
5493 name, combine);
5494 ctxt->nbErrors++;
5495 }
5496 xmlFree(combine);
5497 } else {
5498 if (missing == 0)
5499 missing = 1;
5500 else {
5501 if (ctxt->error != NULL)
5502 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005503 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005504 name);
5505 ctxt->nbErrors++;
5506 }
5507 }
5508
5509 cur = cur->nextHash;
5510 }
5511#ifdef DEBUG
5512 xmlGenericError(xmlGenericErrorContext,
5513 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5514 name, choiceOrInterleave);
5515#endif
5516 if (choiceOrInterleave == -1)
5517 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005518 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005519 if (cur == NULL)
5520 return;
5521 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005522 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005523 else
5524 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005525 tmp = define;
5526 last = NULL;
5527 while (tmp != NULL) {
5528 if (tmp->content != NULL) {
5529 if (tmp->content->next != NULL) {
5530 /*
5531 * we need first to create a wrapper.
5532 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005533 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005534 if (tmp2 == NULL)
5535 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005536 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005537 tmp2->content = tmp->content;
5538 } else {
5539 tmp2 = tmp->content;
5540 }
5541 if (last == NULL) {
5542 cur->content = tmp2;
5543 } else {
5544 last->next = tmp2;
5545 }
5546 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005547 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005548 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005549 tmp = tmp->nextHash;
5550 }
5551 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005552 if (choiceOrInterleave == 0) {
5553 if (ctxt->interleaves == NULL)
5554 ctxt->interleaves = xmlHashCreate(10);
5555 if (ctxt->interleaves == NULL) {
5556 if (ctxt->error != NULL)
5557 ctxt->error(ctxt->userData,
5558 "Failed to create interleaves hash table\n");
5559 ctxt->nbErrors++;
5560 } else {
5561 char tmpname[32];
5562
5563 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5564 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5565 if (ctxt->error != NULL)
5566 ctxt->error(ctxt->userData,
5567 "Failed to add %s to hash table\n", tmpname);
5568 ctxt->nbErrors++;
5569 }
5570 }
5571 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005572}
5573
5574/**
5575 * xmlRelaxNGCombineStart:
5576 * @ctxt: a Relax-NG parser context
5577 * @grammar: the grammar
5578 *
5579 * Applies the 4.17. combine rule for all the start
5580 * element of a given grammar.
5581 */
5582static void
5583xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5584 xmlRelaxNGGrammarPtr grammar) {
5585 xmlRelaxNGDefinePtr starts;
5586 xmlChar *combine;
5587 int choiceOrInterleave = -1;
5588 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005589 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005590
Daniel Veillard2df2de22003-02-17 23:34:33 +00005591 starts = grammar->start;
5592 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005593 return;
5594 cur = starts;
5595 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005596 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5597 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5598 combine = NULL;
5599 if (ctxt->error != NULL)
5600 ctxt->error(ctxt->userData,
5601 "Internal error: start element not found\n");
5602 ctxt->nbErrors++;
5603 } else {
5604 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5605 }
5606
Daniel Veillard6eadf632003-01-23 18:29:16 +00005607 if (combine != NULL) {
5608 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5609 if (choiceOrInterleave == -1)
5610 choiceOrInterleave = 1;
5611 else if (choiceOrInterleave == 0) {
5612 if (ctxt->error != NULL)
5613 ctxt->error(ctxt->userData,
5614 "<start> use both 'choice' and 'interleave'\n");
5615 ctxt->nbErrors++;
5616 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005617 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005618 if (choiceOrInterleave == -1)
5619 choiceOrInterleave = 0;
5620 else if (choiceOrInterleave == 1) {
5621 if (ctxt->error != NULL)
5622 ctxt->error(ctxt->userData,
5623 "<start> use both 'choice' and 'interleave'\n");
5624 ctxt->nbErrors++;
5625 }
5626 } else {
5627 if (ctxt->error != NULL)
5628 ctxt->error(ctxt->userData,
5629 "<start> uses unknown combine value '%s''\n", combine);
5630 ctxt->nbErrors++;
5631 }
5632 xmlFree(combine);
5633 } else {
5634 if (missing == 0)
5635 missing = 1;
5636 else {
5637 if (ctxt->error != NULL)
5638 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005639 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005640 ctxt->nbErrors++;
5641 }
5642 }
5643
Daniel Veillard2df2de22003-02-17 23:34:33 +00005644 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005645 }
5646#ifdef DEBUG
5647 xmlGenericError(xmlGenericErrorContext,
5648 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5649 choiceOrInterleave);
5650#endif
5651 if (choiceOrInterleave == -1)
5652 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005653 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005654 if (cur == NULL)
5655 return;
5656 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005657 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005658 else
5659 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005660 cur->content = grammar->start;
5661 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005662 if (choiceOrInterleave == 0) {
5663 if (ctxt->interleaves == NULL)
5664 ctxt->interleaves = xmlHashCreate(10);
5665 if (ctxt->interleaves == NULL) {
5666 if (ctxt->error != NULL)
5667 ctxt->error(ctxt->userData,
5668 "Failed to create interleaves hash table\n");
5669 ctxt->nbErrors++;
5670 } else {
5671 char tmpname[32];
5672
5673 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5674 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5675 if (ctxt->error != NULL)
5676 ctxt->error(ctxt->userData,
5677 "Failed to add %s to hash table\n", tmpname);
5678 ctxt->nbErrors++;
5679 }
5680 }
5681 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005682}
5683
5684/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005685 * xmlRelaxNGCheckCycles:
5686 * @ctxt: a Relax-NG parser context
5687 * @nodes: grammar children nodes
5688 * @depth: the counter
5689 *
5690 * Check for cycles.
5691 *
5692 * Returns 0 if check passed, and -1 in case of error
5693 */
5694static int
5695xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5696 xmlRelaxNGDefinePtr cur, int depth) {
5697 int ret = 0;
5698
5699 while ((ret == 0) && (cur != NULL)) {
5700 if ((cur->type == XML_RELAXNG_REF) ||
5701 (cur->type == XML_RELAXNG_PARENTREF)) {
5702 if (cur->depth == -1) {
5703 cur->depth = depth;
5704 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5705 cur->depth = -2;
5706 } else if (depth == cur->depth) {
5707 if (ctxt->error != NULL)
5708 ctxt->error(ctxt->userData,
5709 "Detected a cycle in %s references\n", cur->name);
5710 ctxt->nbErrors++;
5711 return(-1);
5712 }
5713 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5714 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5715 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005716 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005717 }
5718 cur = cur->next;
5719 }
5720 return(ret);
5721}
5722
5723/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005724 * xmlRelaxNGTryUnlink:
5725 * @ctxt: a Relax-NG parser context
5726 * @cur: the definition to unlink
5727 * @parent: the parent definition
5728 * @prev: the previous sibling definition
5729 *
5730 * Try to unlink a definition. If not possble make it a NOOP
5731 *
5732 * Returns the new prev definition
5733 */
5734static xmlRelaxNGDefinePtr
5735xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5736 xmlRelaxNGDefinePtr cur,
5737 xmlRelaxNGDefinePtr parent,
5738 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005739 if (prev != NULL) {
5740 prev->next = cur->next;
5741 } else {
5742 if (parent != NULL) {
5743 if (parent->content == cur)
5744 parent->content = cur->next;
5745 else if (parent->attrs == cur)
5746 parent->attrs = cur->next;
5747 else if (parent->nameClass == cur)
5748 parent->nameClass = cur->next;
5749 } else {
5750 cur->type = XML_RELAXNG_NOOP;
5751 prev = cur;
5752 }
5753 }
5754 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005755}
5756
5757/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005758 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005759 * @ctxt: a Relax-NG parser context
5760 * @nodes: grammar children nodes
5761 *
5762 * Check for simplification of empty and notAllowed
5763 */
5764static void
5765xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5766 xmlRelaxNGDefinePtr cur,
5767 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005768 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005769
Daniel Veillardfd573f12003-03-16 17:52:32 +00005770 while (cur != NULL) {
5771 if ((cur->type == XML_RELAXNG_REF) ||
5772 (cur->type == XML_RELAXNG_PARENTREF)) {
5773 if (cur->depth != -3) {
5774 cur->depth = -3;
5775 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005776 }
5777 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005778 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005779 if ((parent != NULL) &&
5780 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5781 (parent->type == XML_RELAXNG_LIST) ||
5782 (parent->type == XML_RELAXNG_GROUP) ||
5783 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005784 (parent->type == XML_RELAXNG_ONEORMORE) ||
5785 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005786 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005787 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005788 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005789 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005790 (parent->type == XML_RELAXNG_CHOICE)) {
5791 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5792 } else
5793 prev = cur;
5794 } else if (cur->type == XML_RELAXNG_EMPTY){
5795 cur->parent = parent;
5796 if ((parent != NULL) &&
5797 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5798 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005799 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005800 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005801 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005802 if ((parent != NULL) &&
5803 ((parent->type == XML_RELAXNG_GROUP) ||
5804 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5805 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5806 } else
5807 prev = cur;
5808 } else {
5809 cur->parent = parent;
5810 if (cur->content != NULL)
5811 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005812 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005813 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5814 if (cur->nameClass != NULL)
5815 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5816 /*
Daniel Veillardce192eb2003-04-16 15:58:05 +00005817 * On Elements, try to move attribute only generating rules on
5818 * the attrs rules.
5819 */
5820 if (cur->type == XML_RELAXNG_ELEMENT) {
5821 int attronly;
5822 xmlRelaxNGDefinePtr tmp, pre;
5823
5824 while (cur->content != NULL) {
5825 attronly = xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5826 if (attronly == 1) {
5827 /*
5828 * migrate cur->content to attrs
5829 */
5830 tmp = cur->content;
5831 cur->content = tmp->next;
5832 tmp->next = cur->attrs;
5833 cur->attrs = tmp;
5834 } else {
5835 /*
5836 * cur->content can generate elements or text
5837 */
5838 break;
5839 }
5840 }
5841 pre = cur->content;
5842 while ((pre != NULL) && (pre->next != NULL)) {
5843 tmp = pre->next;
5844 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5845 if (attronly == 1) {
5846 /*
5847 * migrate tmp to attrs
5848 */
5849 pre->next = tmp->next;
5850 tmp->next = cur->attrs;
5851 cur->attrs = tmp;
5852 } else {
5853 pre = tmp;
5854 }
5855 }
5856 }
5857 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00005858 * This may result in a simplification
5859 */
5860 if ((cur->type == XML_RELAXNG_GROUP) ||
5861 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5862 if (cur->content == NULL)
5863 cur->type = XML_RELAXNG_EMPTY;
5864 else if (cur->content->next == NULL) {
5865 if ((parent == NULL) && (prev == NULL)) {
5866 cur->type = XML_RELAXNG_NOOP;
5867 } else if (prev == NULL) {
5868 parent->content = cur->content;
5869 cur->content->next = cur->next;
5870 cur = cur->content;
5871 } else {
5872 cur->content->next = cur->next;
5873 prev->next = cur->content;
5874 cur = cur->content;
5875 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005876 }
5877 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005878 /*
5879 * the current node may have been transformed back
5880 */
5881 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5882 (cur->content != NULL) &&
5883 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5884 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5885 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5886 if ((parent != NULL) &&
5887 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5888 (parent->type == XML_RELAXNG_LIST) ||
5889 (parent->type == XML_RELAXNG_GROUP) ||
5890 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5891 (parent->type == XML_RELAXNG_ONEORMORE) ||
5892 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5893 parent->type = XML_RELAXNG_NOT_ALLOWED;
5894 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005895 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005896 if ((parent != NULL) &&
5897 (parent->type == XML_RELAXNG_CHOICE)) {
5898 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5899 } else
5900 prev = cur;
5901 } else if (cur->type == XML_RELAXNG_EMPTY){
5902 if ((parent != NULL) &&
5903 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5904 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5905 parent->type = XML_RELAXNG_EMPTY;
5906 break;
5907 }
5908 if ((parent != NULL) &&
5909 ((parent->type == XML_RELAXNG_GROUP) ||
5910 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5911 (parent->type == XML_RELAXNG_CHOICE))) {
5912 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5913 } else
5914 prev = cur;
5915 } else {
5916 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005917 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005918 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005919 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005920 }
5921}
5922
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005923/**
5924 * xmlRelaxNGGroupContentType:
5925 * @ct1: the first content type
5926 * @ct2: the second content type
5927 *
5928 * Try to group 2 content types
5929 *
5930 * Returns the content type
5931 */
5932static xmlRelaxNGContentType
5933xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5934 xmlRelaxNGContentType ct2) {
5935 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5936 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5937 return(XML_RELAXNG_CONTENT_ERROR);
5938 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5939 return(ct2);
5940 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5941 return(ct1);
5942 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5943 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5944 return(XML_RELAXNG_CONTENT_COMPLEX);
5945 return(XML_RELAXNG_CONTENT_ERROR);
5946}
5947
5948/**
5949 * xmlRelaxNGMaxContentType:
5950 * @ct1: the first content type
5951 * @ct2: the second content type
5952 *
5953 * Compute the max content-type
5954 *
5955 * Returns the content type
5956 */
5957static xmlRelaxNGContentType
5958xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5959 xmlRelaxNGContentType ct2) {
5960 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5961 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5962 return(XML_RELAXNG_CONTENT_ERROR);
5963 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5964 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5965 return(XML_RELAXNG_CONTENT_SIMPLE);
5966 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5967 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5968 return(XML_RELAXNG_CONTENT_COMPLEX);
5969 return(XML_RELAXNG_CONTENT_EMPTY);
5970}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005971
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005972/**
5973 * xmlRelaxNGCheckRules:
5974 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005975 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005976 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005977 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005978 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005979 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005980 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005981 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005982 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005983static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005984xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5985 xmlRelaxNGDefinePtr cur, int flags,
5986 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005987 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005988 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005989
Daniel Veillardfd573f12003-03-16 17:52:32 +00005990 while (cur != NULL) {
5991 ret = XML_RELAXNG_CONTENT_EMPTY;
5992 if ((cur->type == XML_RELAXNG_REF) ||
5993 (cur->type == XML_RELAXNG_PARENTREF)) {
5994 if (flags & XML_RELAXNG_IN_LIST) {
5995 if (ctxt->error != NULL)
5996 ctxt->error(ctxt->userData,
5997 "Found forbidden pattern list//ref\n");
5998 ctxt->nbErrors++;
5999 }
6000 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6001 if (ctxt->error != NULL)
6002 ctxt->error(ctxt->userData,
6003 "Found forbidden pattern data/except//ref\n");
6004 ctxt->nbErrors++;
6005 }
6006 if (cur->depth > -4) {
6007 cur->depth = -4;
6008 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6009 flags, cur->type);
6010 cur->depth = ret - 15 ;
6011 } else if (cur->depth == -4) {
6012 ret = XML_RELAXNG_CONTENT_COMPLEX;
6013 } else {
6014 ret = (xmlRelaxNGContentType) cur->depth + 15;
6015 }
6016 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6017 /*
6018 * The 7.3 Attribute derivation rule for groups is plugged there
6019 */
6020 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6021 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6022 if (ctxt->error != NULL)
6023 ctxt->error(ctxt->userData,
6024 "Found forbidden pattern data/except//element(ref)\n");
6025 ctxt->nbErrors++;
6026 }
6027 if (flags & XML_RELAXNG_IN_LIST) {
6028 if (ctxt->error != NULL)
6029 ctxt->error(ctxt->userData,
6030 "Found forbidden pattern list//element(ref)\n");
6031 ctxt->nbErrors++;
6032 }
6033 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6034 if (ctxt->error != NULL)
6035 ctxt->error(ctxt->userData,
6036 "Found forbidden pattern attribute//element(ref)\n");
6037 ctxt->nbErrors++;
6038 }
6039 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6040 if (ctxt->error != NULL)
6041 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00006042 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006043 ctxt->nbErrors++;
6044 }
6045 /*
6046 * reset since in the simple form elements are only child
6047 * of grammar/define
6048 */
6049 nflags = 0;
6050 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6051 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6052 if (ctxt->error != NULL)
6053 ctxt->error(ctxt->userData,
6054 "Element %s attributes have a content type error\n",
6055 cur->name);
6056 ctxt->nbErrors++;
6057 }
6058 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6059 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6060 if (ctxt->error != NULL)
6061 ctxt->error(ctxt->userData,
6062 "Element %s has a content type error\n",
6063 cur->name);
6064 ctxt->nbErrors++;
6065 } else {
6066 ret = XML_RELAXNG_CONTENT_COMPLEX;
6067 }
6068 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6069 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6070 if (ctxt->error != NULL)
6071 ctxt->error(ctxt->userData,
6072 "Found forbidden pattern attribute//attribute\n");
6073 ctxt->nbErrors++;
6074 }
6075 if (flags & XML_RELAXNG_IN_LIST) {
6076 if (ctxt->error != NULL)
6077 ctxt->error(ctxt->userData,
6078 "Found forbidden pattern list//attribute\n");
6079 ctxt->nbErrors++;
6080 }
6081 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6082 if (ctxt->error != NULL)
6083 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006084 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006085 ctxt->nbErrors++;
6086 }
6087 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6088 if (ctxt->error != NULL)
6089 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006090 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006091 ctxt->nbErrors++;
6092 }
6093 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6094 if (ctxt->error != NULL)
6095 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006096 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006097 ctxt->nbErrors++;
6098 }
6099 if (flags & XML_RELAXNG_IN_START) {
6100 if (ctxt->error != NULL)
6101 ctxt->error(ctxt->userData,
6102 "Found forbidden pattern start//attribute\n");
6103 ctxt->nbErrors++;
6104 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006105 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
6106 if (cur->ns == NULL) {
6107 if (ctxt->error != NULL)
6108 ctxt->error(ctxt->userData,
6109 "Found anyName attribute without oneOrMore ancestor\n");
6110 ctxt->nbErrors++;
6111 } else {
6112 if (ctxt->error != NULL)
6113 ctxt->error(ctxt->userData,
6114 "Found nsName attribute without oneOrMore ancestor\n");
6115 ctxt->nbErrors++;
6116 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00006117 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006118 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6119 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6120 ret = XML_RELAXNG_CONTENT_EMPTY;
6121 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6122 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6123 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6124 if (ctxt->error != NULL)
6125 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006126 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006127 ctxt->nbErrors++;
6128 }
6129 if (flags & XML_RELAXNG_IN_START) {
6130 if (ctxt->error != NULL)
6131 ctxt->error(ctxt->userData,
6132 "Found forbidden pattern start//oneOrMore\n");
6133 ctxt->nbErrors++;
6134 }
6135 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6136 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6137 ret = xmlRelaxNGGroupContentType(ret, ret);
6138 } else if (cur->type == XML_RELAXNG_LIST) {
6139 if (flags & XML_RELAXNG_IN_LIST) {
6140 if (ctxt->error != NULL)
6141 ctxt->error(ctxt->userData,
6142 "Found forbidden pattern list//list\n");
6143 ctxt->nbErrors++;
6144 }
6145 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6146 if (ctxt->error != NULL)
6147 ctxt->error(ctxt->userData,
6148 "Found forbidden pattern data/except//list\n");
6149 ctxt->nbErrors++;
6150 }
6151 if (flags & XML_RELAXNG_IN_START) {
6152 if (ctxt->error != NULL)
6153 ctxt->error(ctxt->userData,
6154 "Found forbidden pattern start//list\n");
6155 ctxt->nbErrors++;
6156 }
6157 nflags = flags | XML_RELAXNG_IN_LIST;
6158 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6159 } else if (cur->type == XML_RELAXNG_GROUP) {
6160 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6161 if (ctxt->error != NULL)
6162 ctxt->error(ctxt->userData,
6163 "Found forbidden pattern data/except//group\n");
6164 ctxt->nbErrors++;
6165 }
6166 if (flags & XML_RELAXNG_IN_START) {
6167 if (ctxt->error != NULL)
6168 ctxt->error(ctxt->userData,
6169 "Found forbidden pattern start//group\n");
6170 ctxt->nbErrors++;
6171 }
6172 if (flags & XML_RELAXNG_IN_ONEORMORE)
6173 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6174 else
6175 nflags = flags;
6176 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6177 /*
6178 * The 7.3 Attribute derivation rule for groups is plugged there
6179 */
6180 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6181 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6182 if (flags & XML_RELAXNG_IN_LIST) {
6183 if (ctxt->error != NULL)
6184 ctxt->error(ctxt->userData,
6185 "Found forbidden pattern list//interleave\n");
6186 ctxt->nbErrors++;
6187 }
6188 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6189 if (ctxt->error != NULL)
6190 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006191 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006192 ctxt->nbErrors++;
6193 }
6194 if (flags & XML_RELAXNG_IN_START) {
6195 if (ctxt->error != NULL)
6196 ctxt->error(ctxt->userData,
6197 "Found forbidden pattern start//interleave\n");
6198 ctxt->nbErrors++;
6199 }
6200 if (flags & XML_RELAXNG_IN_ONEORMORE)
6201 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6202 else
6203 nflags = flags;
6204 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6205 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6206 if ((cur->parent != NULL) &&
6207 (cur->parent->type == XML_RELAXNG_DATATYPE))
6208 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6209 else
6210 nflags = flags;
6211 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6212 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6213 if (flags & XML_RELAXNG_IN_START) {
6214 if (ctxt->error != NULL)
6215 ctxt->error(ctxt->userData,
6216 "Found forbidden pattern start//data\n");
6217 ctxt->nbErrors++;
6218 }
6219 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6220 ret = XML_RELAXNG_CONTENT_SIMPLE;
6221 } else if (cur->type == XML_RELAXNG_VALUE) {
6222 if (flags & XML_RELAXNG_IN_START) {
6223 if (ctxt->error != NULL)
6224 ctxt->error(ctxt->userData,
6225 "Found forbidden pattern start//value\n");
6226 ctxt->nbErrors++;
6227 }
6228 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6229 ret = XML_RELAXNG_CONTENT_SIMPLE;
6230 } else if (cur->type == XML_RELAXNG_TEXT) {
6231 if (flags & XML_RELAXNG_IN_LIST) {
6232 if (ctxt->error != NULL)
6233 ctxt->error(ctxt->userData,
6234 "Found forbidden pattern list//text\n");
6235 ctxt->nbErrors++;
6236 }
6237 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6238 if (ctxt->error != NULL)
6239 ctxt->error(ctxt->userData,
6240 "Found forbidden pattern data/except//text\n");
6241 ctxt->nbErrors++;
6242 }
6243 if (flags & XML_RELAXNG_IN_START) {
6244 if (ctxt->error != NULL)
6245 ctxt->error(ctxt->userData,
6246 "Found forbidden pattern start//text\n");
6247 ctxt->nbErrors++;
6248 }
6249 ret = XML_RELAXNG_CONTENT_COMPLEX;
6250 } else if (cur->type == XML_RELAXNG_EMPTY) {
6251 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6252 if (ctxt->error != NULL)
6253 ctxt->error(ctxt->userData,
6254 "Found forbidden pattern data/except//empty\n");
6255 ctxt->nbErrors++;
6256 }
6257 if (flags & XML_RELAXNG_IN_START) {
6258 if (ctxt->error != NULL)
6259 ctxt->error(ctxt->userData,
6260 "Found forbidden pattern start//empty\n");
6261 ctxt->nbErrors++;
6262 }
6263 ret = XML_RELAXNG_CONTENT_EMPTY;
6264 } else if (cur->type == XML_RELAXNG_CHOICE) {
6265 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6266 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6267 } else {
6268 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6269 }
6270 cur = cur->next;
6271 if (ptype == XML_RELAXNG_GROUP) {
6272 val = xmlRelaxNGGroupContentType(val, ret);
6273 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6274 tmp = xmlRelaxNGGroupContentType(val, ret);
6275 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6276 tmp = xmlRelaxNGMaxContentType(val, ret);
6277 } else if (ptype == XML_RELAXNG_CHOICE) {
6278 val = xmlRelaxNGMaxContentType(val, ret);
6279 } else if (ptype == XML_RELAXNG_LIST) {
6280 val = XML_RELAXNG_CONTENT_SIMPLE;
6281 } else if (ptype == XML_RELAXNG_EXCEPT) {
6282 if (ret == XML_RELAXNG_CONTENT_ERROR)
6283 val = XML_RELAXNG_CONTENT_ERROR;
6284 else
6285 val = XML_RELAXNG_CONTENT_SIMPLE;
6286 } else {
6287 val = xmlRelaxNGGroupContentType(val, ret);
6288 }
6289
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006290 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006291 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006292}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006293
6294/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006295 * xmlRelaxNGParseGrammar:
6296 * @ctxt: a Relax-NG parser context
6297 * @nodes: grammar children nodes
6298 *
6299 * parse a Relax-NG <grammar> node
6300 *
6301 * Returns the internal xmlRelaxNGGrammarPtr built or
6302 * NULL in case of error
6303 */
6304static xmlRelaxNGGrammarPtr
6305xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6306 xmlRelaxNGGrammarPtr ret, tmp, old;
6307
Daniel Veillardc482e262003-02-26 14:48:48 +00006308#ifdef DEBUG_GRAMMAR
6309 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6310#endif
6311
Daniel Veillard6eadf632003-01-23 18:29:16 +00006312 ret = xmlRelaxNGNewGrammar(ctxt);
6313 if (ret == NULL)
6314 return(NULL);
6315
6316 /*
6317 * Link the new grammar in the tree
6318 */
6319 ret->parent = ctxt->grammar;
6320 if (ctxt->grammar != NULL) {
6321 tmp = ctxt->grammar->children;
6322 if (tmp == NULL) {
6323 ctxt->grammar->children = ret;
6324 } else {
6325 while (tmp->next != NULL)
6326 tmp = tmp->next;
6327 tmp->next = ret;
6328 }
6329 }
6330
6331 old = ctxt->grammar;
6332 ctxt->grammar = ret;
6333 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6334 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006335 if (ctxt->grammar == NULL) {
6336 if (ctxt->error != NULL)
6337 ctxt->error(ctxt->userData,
6338 "Failed to parse <grammar> content\n");
6339 ctxt->nbErrors++;
6340 } else if (ctxt->grammar->start == NULL) {
6341 if (ctxt->error != NULL)
6342 ctxt->error(ctxt->userData,
6343 "Element <grammar> has no <start>\n");
6344 ctxt->nbErrors++;
6345 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006346
6347 /*
6348 * Apply 4.17 mergingd rules to defines and starts
6349 */
6350 xmlRelaxNGCombineStart(ctxt, ret);
6351 if (ret->defs != NULL) {
6352 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6353 ctxt);
6354 }
6355
6356 /*
6357 * link together defines and refs in this grammar
6358 */
6359 if (ret->refs != NULL) {
6360 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6361 ctxt);
6362 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006363
Daniel Veillard6eadf632003-01-23 18:29:16 +00006364 ctxt->grammar = old;
6365 return(ret);
6366}
6367
6368/**
6369 * xmlRelaxNGParseDocument:
6370 * @ctxt: a Relax-NG parser context
6371 * @node: the root node of the RelaxNG schema
6372 *
6373 * parse a Relax-NG definition resource and build an internal
6374 * xmlRelaxNG struture which can be used to validate instances.
6375 *
6376 * Returns the internal XML RelaxNG structure built or
6377 * NULL in case of error
6378 */
6379static xmlRelaxNGPtr
6380xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6381 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006382 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006383 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006384
6385 if ((ctxt == NULL) || (node == NULL))
6386 return (NULL);
6387
6388 schema = xmlRelaxNGNewRelaxNG(ctxt);
6389 if (schema == NULL)
6390 return(NULL);
6391
Daniel Veillard276be4a2003-01-24 01:03:34 +00006392 olddefine = ctxt->define;
6393 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006394 if (IS_RELAXNG(node, "grammar")) {
6395 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6396 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00006397 xmlRelaxNGGrammarPtr tmp, ret;
6398
6399 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006400 if (schema->topgrammar == NULL) {
6401 return(schema);
6402 }
Daniel Veillardc482e262003-02-26 14:48:48 +00006403 /*
6404 * Link the new grammar in the tree
6405 */
6406 ret->parent = ctxt->grammar;
6407 if (ctxt->grammar != NULL) {
6408 tmp = ctxt->grammar->children;
6409 if (tmp == NULL) {
6410 ctxt->grammar->children = ret;
6411 } else {
6412 while (tmp->next != NULL)
6413 tmp = tmp->next;
6414 tmp->next = ret;
6415 }
6416 }
Daniel Veillarde431a272003-01-29 23:02:33 +00006417 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00006418 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006419 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00006420 if (old != NULL)
6421 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006422 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006423 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006424 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006425 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006426 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006427 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6428 while ((schema->topgrammar->start != NULL) &&
6429 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6430 (schema->topgrammar->start->next != NULL))
6431 schema->topgrammar->start = schema->topgrammar->start->content;
6432 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6433 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006434 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006435 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006436
6437#ifdef DEBUG
6438 if (schema == NULL)
6439 xmlGenericError(xmlGenericErrorContext,
6440 "xmlRelaxNGParseDocument() failed\n");
6441#endif
6442
6443 return (schema);
6444}
6445
6446/************************************************************************
6447 * *
6448 * Reading RelaxNGs *
6449 * *
6450 ************************************************************************/
6451
6452/**
6453 * xmlRelaxNGNewParserCtxt:
6454 * @URL: the location of the schema
6455 *
6456 * Create an XML RelaxNGs parse context for that file/resource expected
6457 * to contain an XML RelaxNGs file.
6458 *
6459 * Returns the parser context or NULL in case of error
6460 */
6461xmlRelaxNGParserCtxtPtr
6462xmlRelaxNGNewParserCtxt(const char *URL) {
6463 xmlRelaxNGParserCtxtPtr ret;
6464
6465 if (URL == NULL)
6466 return(NULL);
6467
6468 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6469 if (ret == NULL) {
6470 xmlGenericError(xmlGenericErrorContext,
6471 "Failed to allocate new schama parser context for %s\n", URL);
6472 return (NULL);
6473 }
6474 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6475 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006476 ret->error = xmlGenericError;
6477 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006478 return (ret);
6479}
6480
6481/**
6482 * xmlRelaxNGNewMemParserCtxt:
6483 * @buffer: a pointer to a char array containing the schemas
6484 * @size: the size of the array
6485 *
6486 * Create an XML RelaxNGs parse context for that memory buffer expected
6487 * to contain an XML RelaxNGs file.
6488 *
6489 * Returns the parser context or NULL in case of error
6490 */
6491xmlRelaxNGParserCtxtPtr
6492xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6493 xmlRelaxNGParserCtxtPtr ret;
6494
6495 if ((buffer == NULL) || (size <= 0))
6496 return(NULL);
6497
6498 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6499 if (ret == NULL) {
6500 xmlGenericError(xmlGenericErrorContext,
6501 "Failed to allocate new schama parser context\n");
6502 return (NULL);
6503 }
6504 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6505 ret->buffer = buffer;
6506 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006507 ret->error = xmlGenericError;
6508 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006509 return (ret);
6510}
6511
6512/**
6513 * xmlRelaxNGFreeParserCtxt:
6514 * @ctxt: the schema parser context
6515 *
6516 * Free the resources associated to the schema parser context
6517 */
6518void
6519xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6520 if (ctxt == NULL)
6521 return;
6522 if (ctxt->URL != NULL)
6523 xmlFree(ctxt->URL);
6524 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006525 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006526 if (ctxt->interleaves != NULL)
6527 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006528 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006529 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006530 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006531 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006532 if (ctxt->docTab != NULL)
6533 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006534 if (ctxt->incTab != NULL)
6535 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006536 if (ctxt->defTab != NULL) {
6537 int i;
6538
6539 for (i = 0;i < ctxt->defNr;i++)
6540 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6541 xmlFree(ctxt->defTab);
6542 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006543 xmlFree(ctxt);
6544}
6545
Daniel Veillard6eadf632003-01-23 18:29:16 +00006546/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006547 * xmlRelaxNGNormExtSpace:
6548 * @value: a value
6549 *
6550 * Removes the leading and ending spaces of the value
6551 * The string is modified "in situ"
6552 */
6553static void
6554xmlRelaxNGNormExtSpace(xmlChar *value) {
6555 xmlChar *start = value;
6556 xmlChar *cur = value;
6557 if (value == NULL)
6558 return;
6559
6560 while (IS_BLANK(*cur)) cur++;
6561 if (cur == start) {
6562 do {
6563 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6564 if (*cur == 0)
6565 return;
6566 start = cur;
6567 while (IS_BLANK(*cur)) cur++;
6568 if (*cur == 0) {
6569 *start = 0;
6570 return;
6571 }
6572 } while (1);
6573 } else {
6574 do {
6575 while ((*cur != 0) && (!IS_BLANK(*cur)))
6576 *start++ = *cur++;
6577 if (*cur == 0) {
6578 *start = 0;
6579 return;
6580 }
6581 /* don't try to normalize the inner spaces */
6582 while (IS_BLANK(*cur)) cur++;
6583 *start++ = *cur++;
6584 if (*cur == 0) {
6585 *start = 0;
6586 return;
6587 }
6588 } while (1);
6589 }
6590}
6591
6592/**
6593 * xmlRelaxNGCheckAttributes:
6594 * @ctxt: a Relax-NG parser context
6595 * @node: a Relax-NG node
6596 *
6597 * Check all the attributes on the given node
6598 */
6599static void
6600xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6601 xmlAttrPtr cur, next;
6602
6603 cur = node->properties;
6604 while (cur != NULL) {
6605 next = cur->next;
6606 if ((cur->ns == NULL) ||
6607 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6608 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6609 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6610 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6611 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6612 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006613 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006614 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6615 if (ctxt->error != NULL)
6616 ctxt->error(ctxt->userData,
6617 "Attribute %s is not allowed on %s\n",
6618 cur->name, node->name);
6619 ctxt->nbErrors++;
6620 }
6621 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6622 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6623 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6624 if (ctxt->error != NULL)
6625 ctxt->error(ctxt->userData,
6626 "Attribute %s is not allowed on %s\n",
6627 cur->name, node->name);
6628 ctxt->nbErrors++;
6629 }
6630 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6631 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6632 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6633 if (ctxt->error != NULL)
6634 ctxt->error(ctxt->userData,
6635 "Attribute %s is not allowed on %s\n",
6636 cur->name, node->name);
6637 ctxt->nbErrors++;
6638 }
6639 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6640 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6641 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6642 if (ctxt->error != NULL)
6643 ctxt->error(ctxt->userData,
6644 "Attribute %s is not allowed on %s\n",
6645 cur->name, node->name);
6646 ctxt->nbErrors++;
6647 }
6648 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6649 xmlChar *val;
6650 xmlURIPtr uri;
6651
6652 val = xmlNodeListGetString(node->doc, cur->children, 1);
6653 if (val != NULL) {
6654 if (val[0] != 0) {
6655 uri = xmlParseURI((const char *) val);
6656 if (uri == NULL) {
6657 if (ctxt->error != NULL)
6658 ctxt->error(ctxt->userData,
6659 "Attribute %s contains invalid URI %s\n",
6660 cur->name, val);
6661 ctxt->nbErrors++;
6662 } else {
6663 if (uri->scheme == NULL) {
6664 if (ctxt->error != NULL)
6665 ctxt->error(ctxt->userData,
6666 "Attribute %s URI %s is not absolute\n",
6667 cur->name, val);
6668 ctxt->nbErrors++;
6669 }
6670 if (uri->fragment != NULL) {
6671 if (ctxt->error != NULL)
6672 ctxt->error(ctxt->userData,
6673 "Attribute %s URI %s has a fragment ID\n",
6674 cur->name, val);
6675 ctxt->nbErrors++;
6676 }
6677 xmlFreeURI(uri);
6678 }
6679 }
6680 xmlFree(val);
6681 }
6682 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6683 if (ctxt->error != NULL)
6684 ctxt->error(ctxt->userData,
6685 "Unknown attribute %s on %s\n",
6686 cur->name, node->name);
6687 ctxt->nbErrors++;
6688 }
6689 }
6690 cur = next;
6691 }
6692}
6693
6694/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006695 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006696 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006697 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006698 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006699 * Cleanup the subtree from unwanted nodes for parsing, resolve
6700 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006701 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006702static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006703xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006704 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006705
Daniel Veillard6eadf632003-01-23 18:29:16 +00006706 delete = NULL;
6707 cur = root;
6708 while (cur != NULL) {
6709 if (delete != NULL) {
6710 xmlUnlinkNode(delete);
6711 xmlFreeNode(delete);
6712 delete = NULL;
6713 }
6714 if (cur->type == XML_ELEMENT_NODE) {
6715 /*
6716 * Simplification 4.1. Annotations
6717 */
6718 if ((cur->ns == NULL) ||
6719 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006720 if ((cur->parent != NULL) &&
6721 (cur->parent->type == XML_ELEMENT_NODE) &&
6722 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6723 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6724 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6725 if (ctxt->error != NULL)
6726 ctxt->error(ctxt->userData,
6727 "element %s doesn't allow foreign elements\n",
6728 cur->parent->name);
6729 ctxt->nbErrors++;
6730 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006731 delete = cur;
6732 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006733 } else {
6734 xmlRelaxNGCleanupAttributes(ctxt, cur);
6735 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6736 xmlChar *href, *ns, *base, *URL;
6737 xmlRelaxNGDocumentPtr docu;
6738 xmlNodePtr tmp;
6739
6740 ns = xmlGetProp(cur, BAD_CAST "ns");
6741 if (ns == NULL) {
6742 tmp = cur->parent;
6743 while ((tmp != NULL) &&
6744 (tmp->type == XML_ELEMENT_NODE)) {
6745 ns = xmlGetProp(tmp, BAD_CAST "ns");
6746 if (ns != NULL)
6747 break;
6748 tmp = tmp->parent;
6749 }
6750 }
6751 href = xmlGetProp(cur, BAD_CAST "href");
6752 if (href == NULL) {
6753 if (ctxt->error != NULL)
6754 ctxt->error(ctxt->userData,
6755 "xmlRelaxNGParse: externalRef has no href attribute\n");
6756 ctxt->nbErrors++;
6757 delete = cur;
6758 goto skip_children;
6759 }
6760 base = xmlNodeGetBase(cur->doc, cur);
6761 URL = xmlBuildURI(href, base);
6762 if (URL == NULL) {
6763 if (ctxt->error != NULL)
6764 ctxt->error(ctxt->userData,
6765 "Failed to compute URL for externalRef %s\n", href);
6766 ctxt->nbErrors++;
6767 if (href != NULL)
6768 xmlFree(href);
6769 if (base != NULL)
6770 xmlFree(base);
6771 delete = cur;
6772 goto skip_children;
6773 }
6774 if (href != NULL)
6775 xmlFree(href);
6776 if (base != NULL)
6777 xmlFree(base);
6778 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6779 if (docu == NULL) {
6780 if (ctxt->error != NULL)
6781 ctxt->error(ctxt->userData,
6782 "Failed to load externalRef %s\n", URL);
6783 ctxt->nbErrors++;
6784 xmlFree(URL);
6785 delete = cur;
6786 goto skip_children;
6787 }
6788 if (ns != NULL)
6789 xmlFree(ns);
6790 xmlFree(URL);
6791 cur->_private = docu;
6792 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6793 xmlChar *href, *ns, *base, *URL;
6794 xmlRelaxNGIncludePtr incl;
6795 xmlNodePtr tmp;
6796
6797 href = xmlGetProp(cur, BAD_CAST "href");
6798 if (href == NULL) {
6799 if (ctxt->error != NULL)
6800 ctxt->error(ctxt->userData,
6801 "xmlRelaxNGParse: include has no href attribute\n");
6802 ctxt->nbErrors++;
6803 delete = cur;
6804 goto skip_children;
6805 }
6806 base = xmlNodeGetBase(cur->doc, cur);
6807 URL = xmlBuildURI(href, base);
6808 if (URL == NULL) {
6809 if (ctxt->error != NULL)
6810 ctxt->error(ctxt->userData,
6811 "Failed to compute URL for include %s\n", href);
6812 ctxt->nbErrors++;
6813 if (href != NULL)
6814 xmlFree(href);
6815 if (base != NULL)
6816 xmlFree(base);
6817 delete = cur;
6818 goto skip_children;
6819 }
6820 if (href != NULL)
6821 xmlFree(href);
6822 if (base != NULL)
6823 xmlFree(base);
6824 ns = xmlGetProp(cur, BAD_CAST "ns");
6825 if (ns == NULL) {
6826 tmp = cur->parent;
6827 while ((tmp != NULL) &&
6828 (tmp->type == XML_ELEMENT_NODE)) {
6829 ns = xmlGetProp(tmp, BAD_CAST "ns");
6830 if (ns != NULL)
6831 break;
6832 tmp = tmp->parent;
6833 }
6834 }
6835 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6836 if (ns != NULL)
6837 xmlFree(ns);
6838 if (incl == NULL) {
6839 if (ctxt->error != NULL)
6840 ctxt->error(ctxt->userData,
6841 "Failed to load include %s\n", URL);
6842 ctxt->nbErrors++;
6843 xmlFree(URL);
6844 delete = cur;
6845 goto skip_children;
6846 }
6847 xmlFree(URL);
6848 cur->_private = incl;
6849 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6850 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6851 xmlChar *name, *ns;
6852 xmlNodePtr text = NULL;
6853
6854 /*
6855 * Simplification 4.8. name attribute of element
6856 * and attribute elements
6857 */
6858 name = xmlGetProp(cur, BAD_CAST "name");
6859 if (name != NULL) {
6860 if (cur->children == NULL) {
6861 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6862 name);
6863 } else {
6864 xmlNodePtr node;
6865 node = xmlNewNode(cur->ns, BAD_CAST "name");
6866 if (node != NULL) {
6867 xmlAddPrevSibling(cur->children, node);
6868 text = xmlNewText(name);
6869 xmlAddChild(node, text);
6870 text = node;
6871 }
6872 }
6873 if (text == NULL) {
6874 if (ctxt->error != NULL)
6875 ctxt->error(ctxt->userData,
6876 "Failed to create a name %s element\n", name);
6877 ctxt->nbErrors++;
6878 }
6879 xmlUnsetProp(cur, BAD_CAST "name");
6880 xmlFree(name);
6881 ns = xmlGetProp(cur, BAD_CAST "ns");
6882 if (ns != NULL) {
6883 if (text != NULL) {
6884 xmlSetProp(text, BAD_CAST "ns", ns);
6885 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6886 }
6887 xmlFree(ns);
6888 } else if (xmlStrEqual(cur->name,
6889 BAD_CAST "attribute")) {
6890 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6891 }
6892 }
6893 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6894 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6895 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6896 /*
6897 * Simplification 4.8. name attribute of element
6898 * and attribute elements
6899 */
6900 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6901 xmlNodePtr node;
6902 xmlChar *ns = NULL;
6903
6904 node = cur->parent;
6905 while ((node != NULL) &&
6906 (node->type == XML_ELEMENT_NODE)) {
6907 ns = xmlGetProp(node, BAD_CAST "ns");
6908 if (ns != NULL) {
6909 break;
6910 }
6911 node = node->parent;
6912 }
6913 if (ns == NULL) {
6914 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6915 } else {
6916 xmlSetProp(cur, BAD_CAST "ns", ns);
6917 xmlFree(ns);
6918 }
6919 }
6920 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6921 xmlChar *name, *local, *prefix;
6922
6923 /*
6924 * Simplification: 4.10. QNames
6925 */
6926 name = xmlNodeGetContent(cur);
6927 if (name != NULL) {
6928 local = xmlSplitQName2(name, &prefix);
6929 if (local != NULL) {
6930 xmlNsPtr ns;
6931
6932 ns = xmlSearchNs(cur->doc, cur, prefix);
6933 if (ns == NULL) {
6934 if (ctxt->error != NULL)
6935 ctxt->error(ctxt->userData,
6936 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6937 ctxt->nbErrors++;
6938 } else {
6939 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6940 xmlNodeSetContent(cur, local);
6941 }
6942 xmlFree(local);
6943 xmlFree(prefix);
6944 }
6945 xmlFree(name);
6946 }
6947 }
6948 /*
6949 * 4.16
6950 */
6951 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6952 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6953 if (ctxt->error != NULL)
6954 ctxt->error(ctxt->userData,
6955 "Found nsName/except//nsName forbidden construct\n");
6956 ctxt->nbErrors++;
6957 }
6958 }
6959 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6960 (cur != root)) {
6961 int oldflags = ctxt->flags;
6962
6963 /*
6964 * 4.16
6965 */
6966 if ((cur->parent != NULL) &&
6967 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6968 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6969 xmlRelaxNGCleanupTree(ctxt, cur);
6970 ctxt->flags = oldflags;
6971 goto skip_children;
6972 } else if ((cur->parent != NULL) &&
6973 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6974 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6975 xmlRelaxNGCleanupTree(ctxt, cur);
6976 ctxt->flags = oldflags;
6977 goto skip_children;
6978 }
6979 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6980 /*
6981 * 4.16
6982 */
6983 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6984 if (ctxt->error != NULL)
6985 ctxt->error(ctxt->userData,
6986 "Found anyName/except//anyName forbidden construct\n");
6987 ctxt->nbErrors++;
6988 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6989 if (ctxt->error != NULL)
6990 ctxt->error(ctxt->userData,
6991 "Found nsName/except//anyName forbidden construct\n");
6992 ctxt->nbErrors++;
6993 }
6994 }
6995 /*
6996 * Thisd is not an else since "include" is transformed
6997 * into a div
6998 */
6999 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7000 xmlChar *ns;
7001 xmlNodePtr child, ins, tmp;
7002
7003 /*
7004 * implements rule 4.11
7005 */
7006
7007 ns = xmlGetProp(cur, BAD_CAST "ns");
7008
7009 child = cur->children;
7010 ins = cur;
7011 while (child != NULL) {
7012 if (ns != NULL) {
7013 if (!xmlHasProp(child, BAD_CAST "ns")) {
7014 xmlSetProp(child, BAD_CAST "ns", ns);
7015 }
7016 }
7017 tmp = child->next;
7018 xmlUnlinkNode(child);
7019 ins = xmlAddNextSibling(ins, child);
7020 child = tmp;
7021 }
7022 if (ns != NULL)
7023 xmlFree(ns);
7024 delete = cur;
7025 goto skip_children;
7026 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007027 }
7028 }
7029 /*
7030 * Simplification 4.2 whitespaces
7031 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007032 else if ((cur->type == XML_TEXT_NODE) ||
7033 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007034 if (IS_BLANK_NODE(cur)) {
7035 if (cur->parent->type == XML_ELEMENT_NODE) {
7036 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
7037 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
7038 delete = cur;
7039 } else {
7040 delete = cur;
7041 goto skip_children;
7042 }
7043 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007044 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007045 delete = cur;
7046 goto skip_children;
7047 }
7048
7049 /*
7050 * Skip to next node
7051 */
7052 if (cur->children != NULL) {
7053 if ((cur->children->type != XML_ENTITY_DECL) &&
7054 (cur->children->type != XML_ENTITY_REF_NODE) &&
7055 (cur->children->type != XML_ENTITY_NODE)) {
7056 cur = cur->children;
7057 continue;
7058 }
7059 }
7060skip_children:
7061 if (cur->next != NULL) {
7062 cur = cur->next;
7063 continue;
7064 }
7065
7066 do {
7067 cur = cur->parent;
7068 if (cur == NULL)
7069 break;
7070 if (cur == root) {
7071 cur = NULL;
7072 break;
7073 }
7074 if (cur->next != NULL) {
7075 cur = cur->next;
7076 break;
7077 }
7078 } while (cur != NULL);
7079 }
7080 if (delete != NULL) {
7081 xmlUnlinkNode(delete);
7082 xmlFreeNode(delete);
7083 delete = NULL;
7084 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007085}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007086
Daniel Veillardc5312d72003-02-21 17:14:10 +00007087/**
7088 * xmlRelaxNGCleanupDoc:
7089 * @ctxt: a Relax-NG parser context
7090 * @doc: an xmldocPtr document pointer
7091 *
7092 * Cleanup the document from unwanted nodes for parsing, resolve
7093 * Include and externalRef lookups.
7094 *
7095 * Returns the cleaned up document or NULL in case of error
7096 */
7097static xmlDocPtr
7098xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
7099 xmlNodePtr root;
7100
7101 /*
7102 * Extract the root
7103 */
7104 root = xmlDocGetRootElement(doc);
7105 if (root == NULL) {
7106 if (ctxt->error != NULL)
7107 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7108 ctxt->URL);
7109 ctxt->nbErrors++;
7110 return (NULL);
7111 }
7112 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007113 return(doc);
7114}
7115
7116/**
7117 * xmlRelaxNGParse:
7118 * @ctxt: a Relax-NG parser context
7119 *
7120 * parse a schema definition resource and build an internal
7121 * XML Shema struture which can be used to validate instances.
7122 * *WARNING* this interface is highly subject to change
7123 *
7124 * Returns the internal XML RelaxNG structure built from the resource or
7125 * NULL in case of error
7126 */
7127xmlRelaxNGPtr
7128xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7129{
7130 xmlRelaxNGPtr ret = NULL;
7131 xmlDocPtr doc;
7132 xmlNodePtr root;
7133
7134 xmlRelaxNGInitTypes();
7135
7136 if (ctxt == NULL)
7137 return (NULL);
7138
7139 /*
7140 * First step is to parse the input document into an DOM/Infoset
7141 */
7142 if (ctxt->URL != NULL) {
7143 doc = xmlParseFile((const char *) ctxt->URL);
7144 if (doc == NULL) {
7145 if (ctxt->error != NULL)
7146 ctxt->error(ctxt->userData,
7147 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7148 ctxt->nbErrors++;
7149 return (NULL);
7150 }
7151 } else if (ctxt->buffer != NULL) {
7152 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7153 if (doc == NULL) {
7154 if (ctxt->error != NULL)
7155 ctxt->error(ctxt->userData,
7156 "xmlRelaxNGParse: could not parse schemas\n");
7157 ctxt->nbErrors++;
7158 return (NULL);
7159 }
7160 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7161 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7162 } else {
7163 if (ctxt->error != NULL)
7164 ctxt->error(ctxt->userData,
7165 "xmlRelaxNGParse: nothing to parse\n");
7166 ctxt->nbErrors++;
7167 return (NULL);
7168 }
7169 ctxt->document = doc;
7170
7171 /*
7172 * Some preprocessing of the document content
7173 */
7174 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7175 if (doc == NULL) {
7176 xmlFreeDoc(ctxt->document);
7177 ctxt->document = NULL;
7178 return(NULL);
7179 }
7180
Daniel Veillard6eadf632003-01-23 18:29:16 +00007181 /*
7182 * Then do the parsing for good
7183 */
7184 root = xmlDocGetRootElement(doc);
7185 if (root == NULL) {
7186 if (ctxt->error != NULL)
7187 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7188 ctxt->URL);
7189 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007190 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007191 return (NULL);
7192 }
7193 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007194 if (ret == NULL) {
7195 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007196 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007197 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007198
7199 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007200 * Check the ref/defines links
7201 */
7202 /*
7203 * try to preprocess interleaves
7204 */
7205 if (ctxt->interleaves != NULL) {
7206 xmlHashScan(ctxt->interleaves,
7207 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7208 }
7209
7210 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007211 * if there was a parsing error return NULL
7212 */
7213 if (ctxt->nbErrors > 0) {
7214 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007215 ctxt->document = NULL;
7216 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007217 return(NULL);
7218 }
7219
7220 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007221 * try to compile (parts of) the schemas
7222 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007223 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7224 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00007225 xmlRelaxNGDefinePtr def;
7226
7227 def = xmlRelaxNGNewDefine(ctxt, NULL);
7228 if (def != NULL) {
7229 def->type = XML_RELAXNG_START;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007230 def->content = ret->topgrammar->start;
7231 ret->topgrammar->start = def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007232 }
7233 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007234 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007235 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007236
7237 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007238 * Transfer the pointer for cleanup at the schema level.
7239 */
7240 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007241 ctxt->document = NULL;
7242 ret->documents = ctxt->documents;
7243 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007244
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007245 ret->includes = ctxt->includes;
7246 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007247 ret->defNr = ctxt->defNr;
7248 ret->defTab = ctxt->defTab;
7249 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007250 if (ctxt->idref == 1)
7251 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007252
7253 return (ret);
7254}
7255
7256/**
7257 * xmlRelaxNGSetParserErrors:
7258 * @ctxt: a Relax-NG validation context
7259 * @err: the error callback
7260 * @warn: the warning callback
7261 * @ctx: contextual data for the callbacks
7262 *
7263 * Set the callback functions used to handle errors for a validation context
7264 */
7265void
7266xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7267 xmlRelaxNGValidityErrorFunc err,
7268 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7269 if (ctxt == NULL)
7270 return;
7271 ctxt->error = err;
7272 ctxt->warning = warn;
7273 ctxt->userData = ctx;
7274}
7275/************************************************************************
7276 * *
7277 * Dump back a compiled form *
7278 * *
7279 ************************************************************************/
7280static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7281
7282/**
7283 * xmlRelaxNGDumpDefines:
7284 * @output: the file output
7285 * @defines: a list of define structures
7286 *
7287 * Dump a RelaxNG structure back
7288 */
7289static void
7290xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7291 while (defines != NULL) {
7292 xmlRelaxNGDumpDefine(output, defines);
7293 defines = defines->next;
7294 }
7295}
7296
7297/**
7298 * xmlRelaxNGDumpDefine:
7299 * @output: the file output
7300 * @define: a define structure
7301 *
7302 * Dump a RelaxNG structure back
7303 */
7304static void
7305xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7306 if (define == NULL)
7307 return;
7308 switch(define->type) {
7309 case XML_RELAXNG_EMPTY:
7310 fprintf(output, "<empty/>\n");
7311 break;
7312 case XML_RELAXNG_NOT_ALLOWED:
7313 fprintf(output, "<notAllowed/>\n");
7314 break;
7315 case XML_RELAXNG_TEXT:
7316 fprintf(output, "<text/>\n");
7317 break;
7318 case XML_RELAXNG_ELEMENT:
7319 fprintf(output, "<element>\n");
7320 if (define->name != NULL) {
7321 fprintf(output, "<name");
7322 if (define->ns != NULL)
7323 fprintf(output, " ns=\"%s\"", define->ns);
7324 fprintf(output, ">%s</name>\n", define->name);
7325 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007326 xmlRelaxNGDumpDefines(output, define->attrs);
7327 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007328 fprintf(output, "</element>\n");
7329 break;
7330 case XML_RELAXNG_LIST:
7331 fprintf(output, "<list>\n");
7332 xmlRelaxNGDumpDefines(output, define->content);
7333 fprintf(output, "</list>\n");
7334 break;
7335 case XML_RELAXNG_ONEORMORE:
7336 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007337 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007338 fprintf(output, "</oneOrMore>\n");
7339 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007340 case XML_RELAXNG_ZEROORMORE:
7341 fprintf(output, "<zeroOrMore>\n");
7342 xmlRelaxNGDumpDefines(output, define->content);
7343 fprintf(output, "</zeroOrMore>\n");
7344 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007345 case XML_RELAXNG_CHOICE:
7346 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007347 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007348 fprintf(output, "</choice>\n");
7349 break;
7350 case XML_RELAXNG_GROUP:
7351 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007352 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007353 fprintf(output, "</group>\n");
7354 break;
7355 case XML_RELAXNG_INTERLEAVE:
7356 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007357 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007358 fprintf(output, "</interleave>\n");
7359 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007360 case XML_RELAXNG_OPTIONAL:
7361 fprintf(output, "<optional>\n");
7362 xmlRelaxNGDumpDefines(output, define->content);
7363 fprintf(output, "</optional>\n");
7364 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007365 case XML_RELAXNG_ATTRIBUTE:
7366 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007367 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007368 fprintf(output, "</attribute>\n");
7369 break;
7370 case XML_RELAXNG_DEF:
7371 fprintf(output, "<define");
7372 if (define->name != NULL)
7373 fprintf(output, " name=\"%s\"", define->name);
7374 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007375 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007376 fprintf(output, "</define>\n");
7377 break;
7378 case XML_RELAXNG_REF:
7379 fprintf(output, "<ref");
7380 if (define->name != NULL)
7381 fprintf(output, " name=\"%s\"", define->name);
7382 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007383 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007384 fprintf(output, "</ref>\n");
7385 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007386 case XML_RELAXNG_PARENTREF:
7387 fprintf(output, "<parentRef");
7388 if (define->name != NULL)
7389 fprintf(output, " name=\"%s\"", define->name);
7390 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007391 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00007392 fprintf(output, "</parentRef>\n");
7393 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007394 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00007395 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007396 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00007397 fprintf(output, "</externalRef>\n");
7398 break;
7399 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007400 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007401 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00007402 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007403 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007404 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007405 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007406 TODO
7407 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007408 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007409 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00007410 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007411 }
7412}
7413
7414/**
7415 * xmlRelaxNGDumpGrammar:
7416 * @output: the file output
7417 * @grammar: a grammar structure
7418 * @top: is this a top grammar
7419 *
7420 * Dump a RelaxNG structure back
7421 */
7422static void
7423xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7424{
7425 if (grammar == NULL)
7426 return;
7427
7428 fprintf(output, "<grammar");
7429 if (top)
7430 fprintf(output,
7431 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7432 switch(grammar->combine) {
7433 case XML_RELAXNG_COMBINE_UNDEFINED:
7434 break;
7435 case XML_RELAXNG_COMBINE_CHOICE:
7436 fprintf(output, " combine=\"choice\"");
7437 break;
7438 case XML_RELAXNG_COMBINE_INTERLEAVE:
7439 fprintf(output, " combine=\"interleave\"");
7440 break;
7441 default:
7442 fprintf(output, " <!-- invalid combine value -->");
7443 }
7444 fprintf(output, ">\n");
7445 if (grammar->start == NULL) {
7446 fprintf(output, " <!-- grammar had no start -->");
7447 } else {
7448 fprintf(output, "<start>\n");
7449 xmlRelaxNGDumpDefine(output, grammar->start);
7450 fprintf(output, "</start>\n");
7451 }
7452 /* TODO ? Dump the defines ? */
7453 fprintf(output, "</grammar>\n");
7454}
7455
7456/**
7457 * xmlRelaxNGDump:
7458 * @output: the file output
7459 * @schema: a schema structure
7460 *
7461 * Dump a RelaxNG structure back
7462 */
7463void
7464xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7465{
7466 if (schema == NULL) {
7467 fprintf(output, "RelaxNG empty or failed to compile\n");
7468 return;
7469 }
7470 fprintf(output, "RelaxNG: ");
7471 if (schema->doc == NULL) {
7472 fprintf(output, "no document\n");
7473 } else if (schema->doc->URL != NULL) {
7474 fprintf(output, "%s\n", schema->doc->URL);
7475 } else {
7476 fprintf(output, "\n");
7477 }
7478 if (schema->topgrammar == NULL) {
7479 fprintf(output, "RelaxNG has no top grammar\n");
7480 return;
7481 }
7482 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7483}
7484
Daniel Veillardfebcca42003-02-16 15:44:18 +00007485/**
7486 * xmlRelaxNGDumpTree:
7487 * @output: the file output
7488 * @schema: a schema structure
7489 *
7490 * Dump the transformed RelaxNG tree.
7491 */
7492void
7493xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7494{
7495 if (schema == NULL) {
7496 fprintf(output, "RelaxNG empty or failed to compile\n");
7497 return;
7498 }
7499 if (schema->doc == NULL) {
7500 fprintf(output, "no document\n");
7501 } else {
7502 xmlDocDump(output, schema->doc);
7503 }
7504}
7505
Daniel Veillard6eadf632003-01-23 18:29:16 +00007506/************************************************************************
7507 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007508 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007509 * *
7510 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007511static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7512 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007513
7514/**
7515 * xmlRelaxNGValidateCompiledCallback:
7516 * @exec: the regular expression instance
7517 * @token: the token which matched
7518 * @transdata: callback data, the define for the subelement if available
7519 @ @inputdata: callback data, the Relax NG validation context
7520 *
7521 * Handle the callback and if needed validate the element children.
7522 */
7523static void
7524xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7525 const xmlChar *token,
7526 void *transdata,
7527 void *inputdata) {
7528 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7529 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7530 int ret;
7531
7532#ifdef DEBUG_COMPILE
7533 xmlGenericError(xmlGenericErrorContext,
7534 "Compiled callback for: '%s'\n", token);
7535#endif
7536 if (ctxt == NULL) {
7537 fprintf(stderr, "callback on %s missing context\n", token);
7538 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7539 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7540 return;
7541 }
7542 if (define == NULL) {
7543 if (token[0] == '#')
7544 return;
7545 fprintf(stderr, "callback on %s missing define\n", token);
7546 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7547 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7548 return;
7549 }
7550 if ((ctxt == NULL) || (define == NULL)) {
7551 fprintf(stderr, "callback on %s missing info\n", token);
7552 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7553 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7554 return;
7555 } else if (define->type != XML_RELAXNG_ELEMENT) {
7556 fprintf(stderr, "callback on %s define is not element\n", token);
7557 if (ctxt->errNo == XML_RELAXNG_OK)
7558 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7559 return;
7560 }
7561 ret = xmlRelaxNGValidateDefinition(ctxt, define);
7562}
7563
7564/**
7565 * xmlRelaxNGValidateCompiledContent:
7566 * @ctxt: the RelaxNG validation context
7567 * @regexp: the regular expression as compiled
7568 * @content: list of children to test against the regexp
7569 *
7570 * Validate the content model of an element or start using the regexp
7571 *
7572 * Returns 0 in case of success, -1 in case of error.
7573 */
7574static int
7575xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7576 xmlRegexpPtr regexp, xmlNodePtr content) {
7577 xmlRegExecCtxtPtr exec;
7578 xmlNodePtr cur;
7579 int ret;
7580
7581 if ((ctxt == NULL) || (regexp == NULL))
7582 return(-1);
7583 exec = xmlRegNewExecCtxt(regexp,
7584 xmlRelaxNGValidateCompiledCallback, ctxt);
7585 cur = content;
7586 while (cur != NULL) {
7587 ctxt->state->seq = cur;
7588 switch (cur->type) {
7589 case XML_TEXT_NODE:
7590 case XML_CDATA_SECTION_NODE:
7591 if (xmlIsBlankNode(cur))
7592 break;
7593 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7594 if (ret < 0) {
7595 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7596 }
7597 break;
7598 case XML_ELEMENT_NODE:
7599 if (cur->ns != NULL) {
7600 ret = xmlRegExecPushString2(exec, cur->name,
7601 cur->ns->href, ctxt);
7602 } else {
7603 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7604 }
7605 if (ret < 0) {
7606 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7607 }
7608 break;
7609 default:
7610 break;
7611 }
7612 if (ret < 0) break;
7613 /*
7614 * Switch to next element
7615 */
7616 cur = cur->next;
7617 }
7618 ret = xmlRegExecPushString(exec, NULL, NULL);
7619 if (ret == 1) {
7620 ret = 0;
7621 ctxt->state->seq = NULL;
7622 } else if (ret == 0) {
7623 /*
Daniel Veillardf4e55762003-04-15 23:32:22 +00007624 * TODO: get some of the names needed to exit the current state of exec
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007625 */
7626 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7627 ret = -1;
7628 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7629 xmlRelaxNGDumpValidError(ctxt);
7630 } else {
7631 ret = -1;
7632 }
7633 xmlRegFreeExecCtxt(exec);
7634 return(ret);
7635}
7636
7637/************************************************************************
7638 * *
7639 * Progressive validation of when possible *
7640 * *
7641 ************************************************************************/
Daniel Veillardf4e55762003-04-15 23:32:22 +00007642static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7643 xmlRelaxNGDefinePtr defines);
7644static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt);
7645
7646/**
7647 * xmlRelaxNGElemPush:
7648 * @ctxt: the validation context
7649 * @exec: the regexp runtime for the new content model
7650 *
7651 * Push a new regexp for the current node content model on the stack
7652 *
7653 * Returns 0 in case of success and -1 in case of error.
7654 */
7655static int
7656xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) {
7657 if (ctxt->elemTab == NULL) {
7658 ctxt->elemMax = 10;
7659 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7660 sizeof(xmlRegExecCtxtPtr));
7661 if (ctxt->elemTab == NULL) {
7662 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7663 return(-1);
7664 }
7665 }
7666 if (ctxt->elemNr >= ctxt->elemMax) {
7667 ctxt->elemMax *= 2;
7668 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7669 ctxt->elemMax * sizeof(xmlRegExecCtxtPtr));
7670 if (ctxt->elemTab == NULL) {
7671 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7672 return(-1);
7673 }
7674 }
7675 ctxt->elemTab[ctxt->elemNr++] = exec;
7676 ctxt->elem = exec;
7677 return(0);
7678}
7679
7680/**
7681 * xmlRelaxNGElemPop:
7682 * @ctxt: the validation context
7683 *
7684 * Pop the regexp of the current node content model from the stack
7685 *
7686 * Returns the exec or NULL if empty
7687 */
7688static xmlRegExecCtxtPtr
7689xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) {
7690 xmlRegExecCtxtPtr ret;
7691
7692 if (ctxt->elemNr <= 0) return(NULL);
7693 ctxt->elemNr--;
7694 ret = ctxt->elemTab[ctxt->elemNr];
7695 ctxt->elemTab[ctxt->elemNr] = NULL;
7696 if (ctxt->elemNr > 0)
7697 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7698 else
7699 ctxt->elem = NULL;
7700 return(ret);
7701}
7702
7703/**
7704 * xmlRelaxNGValidateProgressiveCallback:
7705 * @exec: the regular expression instance
7706 * @token: the token which matched
7707 * @transdata: callback data, the define for the subelement if available
7708 @ @inputdata: callback data, the Relax NG validation context
7709 *
7710 * Handle the callback and if needed validate the element children.
7711 * some of the in/out informations are passed via the context in @inputdata.
7712 */
7713static void
7714xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7715 const xmlChar *token,
7716 void *transdata,
7717 void *inputdata) {
7718 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7719 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007720 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007721 xmlNodePtr node = ctxt->pnode;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007722 int ret, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007723
7724#ifdef DEBUG_PROGRESSIVE
7725 xmlGenericError(xmlGenericErrorContext,
7726 "Progressive callback for: '%s'\n", token);
7727#endif
7728 if (ctxt == NULL) {
7729 fprintf(stderr, "callback on %s missing context\n", token);
7730 return;
7731 }
7732 ctxt->pstate = 1;
7733 if (define == NULL) {
7734 if (token[0] == '#')
7735 return;
7736 fprintf(stderr, "callback on %s missing define\n", token);
7737 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7738 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7739 ctxt->pstate = -1;
7740 return;
7741 }
7742 if ((ctxt == NULL) || (define == NULL)) {
7743 fprintf(stderr, "callback on %s missing info\n", token);
7744 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7745 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7746 ctxt->pstate = -1;
7747 return;
7748 } else if (define->type != XML_RELAXNG_ELEMENT) {
7749 fprintf(stderr, "callback on %s define is not element\n", token);
7750 if (ctxt->errNo == XML_RELAXNG_OK)
7751 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7752 ctxt->pstate = -1;
7753 return;
7754 }
7755 if (node->type != XML_ELEMENT_NODE) {
7756 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7757 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7758 xmlRelaxNGDumpValidError(ctxt);
7759 ctxt->pstate = -1;
7760 return;
7761 }
7762 if (define->contModel == NULL) {
7763 /*
7764 * this node cannot be validated in a streamable fashion
7765 */
7766#ifdef DEBUG_PROGRESSIVE
7767 xmlGenericError(xmlGenericErrorContext,
7768 "Element '%s' validation is not streamable\n", token);
7769#endif
7770 ctxt->pstate = 0;
7771 ctxt->pdef = define;
7772 return;
7773 }
7774 exec = xmlRegNewExecCtxt(define->contModel,
7775 xmlRelaxNGValidateProgressiveCallback,
7776 ctxt);
7777 if (exec == NULL) {
7778 ctxt->pstate = -1;
7779 return;
7780 }
7781 xmlRelaxNGElemPush(ctxt, exec);
7782
7783 /*
7784 * Validate the attributes part of the content.
7785 */
7786 state = xmlRelaxNGNewValidState(ctxt, node);
7787 if (state == NULL) {
7788 ctxt->pstate = -1;
7789 return;
7790 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007791 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007792 ctxt->state = state;
7793 if (define->attrs != NULL) {
7794 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7795 if (ret != 0) {
7796 ctxt->pstate = -1;
7797 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7798 }
7799 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007800 if (ctxt->state != NULL) {
7801 ctxt->state->seq = NULL;
7802 ret = xmlRelaxNGValidateElementEnd(ctxt);
7803 if (ret != 0) {
7804 ctxt->pstate = -1;
7805 }
7806 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
7807 } else if (ctxt->states != NULL) {
7808 int tmp = -1, i;
7809
7810 oldflags = ctxt->flags;
7811 ctxt->flags |= FLAGS_IGNORABLE;
7812
7813 for (i = 0; i < ctxt->states->nbState; i++) {
7814 state = ctxt->states->tabState[i];
7815 ctxt->state = state;
7816 ctxt->state->seq = NULL;
7817
7818 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7819 tmp = 0;
7820 xmlRelaxNGFreeValidState(ctxt, state);
7821 }
7822 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7823 ctxt->states = NULL;
7824 if ((ret == 0) && (tmp == -1))
7825 ctxt->pstate = -1;
7826 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007827 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007828 if (ctxt->pstate == -1) {
7829 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
7830 xmlRelaxNGDumpValidError(ctxt);
7831 }
7832 }
7833 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007834}
7835
7836/**
7837 * xmlRelaxNGValidatePushElement:
7838 * @ctxt: the validation context
7839 * @doc: a document instance
7840 * @elem: an element instance
7841 *
7842 * Push a new element start on the RelaxNG validation stack.
7843 *
7844 * returns 1 if no validation problem was found or 0 if validating the
7845 * element requires a full node, and -1 in case of error.
7846 */
7847int
7848xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc,
7849 xmlNodePtr elem)
7850{
7851 int ret = 1;
7852
7853 if ((ctxt == NULL) || (elem == NULL))
7854 return (-1);
7855
7856#ifdef DEBUG_PROGRESSIVE
7857 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
7858#endif
7859 if (ctxt->elem == 0) {
7860 xmlRelaxNGPtr schema;
7861 xmlRelaxNGGrammarPtr grammar;
7862 xmlRegExecCtxtPtr exec;
7863 xmlRelaxNGDefinePtr define;
7864
7865 schema = ctxt->schema;
7866 if (schema == NULL) {
7867 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7868 return (-1);
7869 }
7870 grammar = schema->topgrammar;
7871 if ((grammar == NULL) || (grammar->start == NULL)) {
7872 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7873 return (-1);
7874 }
7875 define = grammar->start;
7876 if (define->contModel == NULL) {
7877 ctxt->pdef = define;
7878 return (0);
7879 }
7880 exec = xmlRegNewExecCtxt(define->contModel,
7881 xmlRelaxNGValidateProgressiveCallback,
7882 ctxt);
7883 if (exec == NULL) {
7884 return (-1);
7885 }
7886 xmlRelaxNGElemPush(ctxt, exec);
7887 }
7888 ctxt->pnode = elem;
7889 ctxt->pstate = 0;
7890 if (elem->ns != NULL) {
7891 ret =
7892 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
7893 ctxt);
7894 } else {
7895 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
7896 }
7897 if (ret < 0) {
7898 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
7899 } else {
7900 if (ctxt->pstate == 0)
7901 ret = 0;
7902 else if (ctxt->pstate < 0)
7903 ret = -1;
7904 else
7905 ret = 1;
7906 }
7907#ifdef DEBUG_PROGRESSIVE
7908 if (ret < 0)
7909 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
7910 elem->name);
7911#endif
7912 return (ret);
7913}
7914
7915/**
7916 * xmlRelaxNGValidatePushCData:
7917 * @ctxt: the RelaxNG validation context
7918 * @data: some character data read
7919 * @len: the lenght of the data
7920 *
7921 * check the CData parsed for validation in the current stack
7922 *
7923 * returns 1 if no validation problem was found or -1 otherwise
7924 */
7925int
7926xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
7927 const xmlChar * data, int len)
7928{
7929 int ret = 1;
7930
7931 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
7932 return (-1);
7933
7934#ifdef DEBUG_PROGRESSIVE
7935 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
7936#endif
7937
7938 while (*data != 0) {
7939 if (!IS_BLANK(*data))
7940 break;
7941 data++;
7942 }
7943 if (*data == 0)
7944 return(1);
7945
7946 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
7947 if (ret < 0) {
7948 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, " TODO ");
7949#ifdef DEBUG_PROGRESSIVE
7950 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
7951#endif
7952
7953 return(-1);
7954 }
7955 return(1);
7956}
7957
7958/**
7959 * xmlRelaxNGValidatePopElement:
7960 * @ctxt: the RelaxNG validation context
7961 * @doc: a document instance
7962 * @elem: an element instance
7963 *
7964 * Pop the element end from the RelaxNG validation stack.
7965 *
7966 * returns 1 if no validation problem was found or 0 otherwise
7967 */
7968int
7969xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
7970 xmlDocPtr doc ATTRIBUTE_UNUSED,
7971 xmlNodePtr elem) {
7972 int ret;
7973 xmlRegExecCtxtPtr exec;
7974
7975 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) return(-1);
7976#ifdef DEBUG_PROGRESSIVE
7977 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
7978#endif
7979 /*
7980 * verify that we reached a terminal state of the content model.
7981 */
7982 exec = xmlRelaxNGElemPop(ctxt);
7983 ret = xmlRegExecPushString(exec, NULL, NULL);
7984 if (ret == 0) {
7985 /*
7986 * TODO: get some of the names needed to exit the current state of exec
7987 */
7988 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7989 ret = -1;
7990 } else if (ret < 0) {
7991 ret = -1;
7992 } else {
7993 ret = 1;
7994 }
7995 xmlRegFreeExecCtxt(exec);
7996#ifdef DEBUG_PROGRESSIVE
7997 if (ret < 0)
7998 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
7999 elem->name);
8000#endif
8001 return(ret);
8002}
8003
8004/**
8005 * xmlRelaxNGValidateFullElement:
8006 * @ctxt: the validation context
8007 * @doc: a document instance
8008 * @elem: an element instance
8009 *
8010 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8011 * 0 and the content of the node has been expanded.
8012 *
8013 * returns 1 if no validation problem was found or -1 in case of error.
8014 */
8015int
8016xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc,
8017 xmlNodePtr elem) {
8018 int ret;
8019 xmlRelaxNGValidStatePtr state;
8020
8021 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) return(-1);
8022#ifdef DEBUG_PROGRESSIVE
8023 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8024#endif
8025 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8026 if (state == NULL) {
8027 return(-1);
8028 }
8029 state->seq = elem;
8030 ctxt->state = state;
8031 ctxt->errNo = XML_RELAXNG_OK;
8032 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8033 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) ret = -1;
8034 else ret = 1;
8035 xmlRelaxNGFreeValidState(ctxt, state);
8036 ctxt->state = NULL;
8037#ifdef DEBUG_PROGRESSIVE
8038 if (ret < 0)
8039 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8040 elem->name);
8041#endif
8042 return(ret);
8043}
8044
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008045/************************************************************************
8046 * *
8047 * Generic interpreted validation implementation *
8048 * *
8049 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008050static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8051 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008052
8053/**
8054 * xmlRelaxNGSkipIgnored:
8055 * @ctxt: a schema validation context
8056 * @node: the top node.
8057 *
8058 * Skip ignorable nodes in that context
8059 *
8060 * Returns the new sibling or NULL in case of error.
8061 */
8062static xmlNodePtr
8063xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8064 xmlNodePtr node) {
8065 /*
8066 * TODO complete and handle entities
8067 */
8068 while ((node != NULL) &&
8069 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008070 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008071 (((node->type == XML_TEXT_NODE) ||
8072 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008073 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8074 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00008075 node = node->next;
8076 }
8077 return(node);
8078}
8079
8080/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008081 * xmlRelaxNGNormalize:
8082 * @ctxt: a schema validation context
8083 * @str: the string to normalize
8084 *
8085 * Implements the normalizeWhiteSpace( s ) function from
8086 * section 6.2.9 of the spec
8087 *
8088 * Returns the new string or NULL in case of error.
8089 */
8090static xmlChar *
8091xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
8092 xmlChar *ret, *p;
8093 const xmlChar *tmp;
8094 int len;
8095
8096 if (str == NULL)
8097 return(NULL);
8098 tmp = str;
8099 while (*tmp != 0) tmp++;
8100 len = tmp - str;
8101
8102 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
8103 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008104 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008105 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008106 } else {
8107 xmlGenericError(xmlGenericErrorContext,
8108 "xmlRelaxNGNormalize: out of memory\n");
8109 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008110 return(NULL);
8111 }
8112 p = ret;
8113 while (IS_BLANK(*str)) str++;
8114 while (*str != 0) {
8115 if (IS_BLANK(*str)) {
8116 while (IS_BLANK(*str)) str++;
8117 if (*str == 0)
8118 break;
8119 *p++ = ' ';
8120 } else
8121 *p++ = *str++;
8122 }
8123 *p = 0;
8124 return(ret);
8125}
8126
8127/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008128 * xmlRelaxNGValidateDatatype:
8129 * @ctxt: a Relax-NG validation context
8130 * @value: the string value
8131 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008132 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008133 *
8134 * Validate the given value against the dataype
8135 *
8136 * Returns 0 if the validation succeeded or an error code.
8137 */
8138static int
8139xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008140 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008141 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008142 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008143 void *result = NULL;
8144 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008145
8146 if ((define == NULL) || (define->data == NULL)) {
8147 return(-1);
8148 }
8149 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008150 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008151 if ((define->attrs != NULL) &&
8152 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008153 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008154 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008155 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008156 }
8157 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008158 ret = -1;
8159 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008160 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008161 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8162 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008163 return(-1);
8164 } else if (ret == 1) {
8165 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008166 } else if (ret == 2) {
8167 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008168 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008169 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008170 ret = -1;
8171 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008172 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008173 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8174 if (lib->facet != NULL) {
8175 tmp = lib->facet(lib->data, define->name, cur->name,
8176 cur->value, value, result);
8177 if (tmp != 0)
8178 ret = -1;
8179 }
8180 cur = cur->next;
8181 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008182 if ((ret == 0) && (define->content != NULL)) {
8183 const xmlChar *oldvalue, *oldendvalue;
8184
8185 oldvalue = ctxt->state->value;
8186 oldendvalue = ctxt->state->endvalue;
8187 ctxt->state->value = (xmlChar *) value;
8188 ctxt->state->endvalue = NULL;
8189 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8190 ctxt->state->value = (xmlChar *) oldvalue;
8191 ctxt->state->endvalue = (xmlChar *) oldendvalue;
8192 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008193 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8194 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008195 return(ret);
8196}
8197
8198/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008199 * xmlRelaxNGNextValue:
8200 * @ctxt: a Relax-NG validation context
8201 *
8202 * Skip to the next value when validating within a list
8203 *
8204 * Returns 0 if the operation succeeded or an error code.
8205 */
8206static int
8207xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
8208 xmlChar *cur;
8209
8210 cur = ctxt->state->value;
8211 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8212 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00008213 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008214 return(0);
8215 }
8216 while (*cur != 0) cur++;
8217 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
8218 if (cur == ctxt->state->endvalue)
8219 ctxt->state->value = NULL;
8220 else
8221 ctxt->state->value = cur;
8222 return(0);
8223}
8224
8225/**
8226 * xmlRelaxNGValidateValueList:
8227 * @ctxt: a Relax-NG validation context
8228 * @defines: the list of definitions to verify
8229 *
8230 * Validate the given set of definitions for the current value
8231 *
8232 * Returns 0 if the validation succeeded or an error code.
8233 */
8234static int
8235xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8236 xmlRelaxNGDefinePtr defines) {
8237 int ret = 0;
8238
8239 while (defines != NULL) {
8240 ret = xmlRelaxNGValidateValue(ctxt, defines);
8241 if (ret != 0)
8242 break;
8243 defines = defines->next;
8244 }
8245 return(ret);
8246}
8247
8248/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008249 * xmlRelaxNGValidateValue:
8250 * @ctxt: a Relax-NG validation context
8251 * @define: the definition to verify
8252 *
8253 * Validate the given definition for the current value
8254 *
8255 * Returns 0 if the validation succeeded or an error code.
8256 */
8257static int
8258xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8259 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00008260 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008261 xmlChar *value;
8262
8263 value = ctxt->state->value;
8264 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008265 case XML_RELAXNG_EMPTY: {
8266 if ((value != NULL) && (value[0] != 0)) {
8267 int idx = 0;
8268
8269 while (IS_BLANK(value[idx]))
8270 idx++;
8271 if (value[idx] != 0)
8272 ret = -1;
8273 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008274 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00008275 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008276 case XML_RELAXNG_TEXT:
8277 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00008278 case XML_RELAXNG_VALUE: {
8279 if (!xmlStrEqual(value, define->value)) {
8280 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008281 xmlRelaxNGTypeLibraryPtr lib;
8282
8283 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00008284 if ((lib != NULL) && (lib->comp != NULL)) {
8285 ret = lib->comp(lib->data, define->name,
8286 define->value, define->node,
8287 (void *) define->attrs,
8288 value, ctxt->state->node);
8289 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00008290 ret = -1;
8291 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008292 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008293 return(-1);
8294 } else if (ret == 1) {
8295 ret = 0;
8296 } else {
8297 ret = -1;
8298 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008299 } else {
8300 xmlChar *nval, *nvalue;
8301
8302 /*
8303 * TODO: trivial optimizations are possible by
8304 * computing at compile-time
8305 */
8306 nval = xmlRelaxNGNormalize(ctxt, define->value);
8307 nvalue = xmlRelaxNGNormalize(ctxt, value);
8308
Daniel Veillardea3f3982003-01-26 19:45:18 +00008309 if ((nval == NULL) || (nvalue == NULL) ||
8310 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00008311 ret = -1;
8312 if (nval != NULL)
8313 xmlFree(nval);
8314 if (nvalue != NULL)
8315 xmlFree(nvalue);
8316 }
8317 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008318 if (ret == 0)
8319 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00008320 break;
8321 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008322 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008323 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8324 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008325 if (ret == 0)
8326 xmlRelaxNGNextValue(ctxt);
8327
8328 break;
8329 }
8330 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008331 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008332 xmlChar *oldvalue;
8333
8334 oldflags = ctxt->flags;
8335 ctxt->flags |= FLAGS_IGNORABLE;
8336
8337 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008338 while (list != NULL) {
8339 ret = xmlRelaxNGValidateValue(ctxt, list);
8340 if (ret == 0) {
8341 break;
8342 }
8343 ctxt->state->value = oldvalue;
8344 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008345 }
8346 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008347 if (ret != 0) {
8348 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8349 xmlRelaxNGDumpValidError(ctxt);
8350 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008351 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008352 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008353 if (ret == 0)
8354 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008355 break;
8356 }
8357 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008358 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008359 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00008360#ifdef DEBUG_LIST
8361 int nb_values = 0;
8362#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008363
8364 oldvalue = ctxt->state->value;
8365 oldend = ctxt->state->endvalue;
8366
8367 val = xmlStrdup(oldvalue);
8368 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008369 val = xmlStrdup(BAD_CAST "");
8370 }
8371 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008372 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008373 return(-1);
8374 }
8375 cur = val;
8376 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00008377 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008378 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008379 cur++;
8380#ifdef DEBUG_LIST
8381 nb_values++;
8382#endif
8383 while (IS_BLANK(*cur))
8384 *cur++ = 0;
8385 } else
8386 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008387 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008388#ifdef DEBUG_LIST
8389 xmlGenericError(xmlGenericErrorContext,
8390 "list value: '%s' found %d items\n", oldvalue, nb_values);
8391 nb_values = 0;
8392#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008393 ctxt->state->endvalue = cur;
8394 cur = val;
8395 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008396
Daniel Veillardfd573f12003-03-16 17:52:32 +00008397 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008398
Daniel Veillardfd573f12003-03-16 17:52:32 +00008399 while (list != NULL) {
8400 if (ctxt->state->value == ctxt->state->endvalue)
8401 ctxt->state->value = NULL;
8402 ret = xmlRelaxNGValidateValue(ctxt, list);
8403 if (ret != 0) {
8404#ifdef DEBUG_LIST
8405 xmlGenericError(xmlGenericErrorContext,
8406 "Failed to validate value: '%s' with %d rule\n",
8407 ctxt->state->value, nb_values);
8408#endif
8409 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008410 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008411#ifdef DEBUG_LIST
8412 nb_values++;
8413#endif
8414 list = list->next;
8415 }
8416
8417 if ((ret == 0) && (ctxt->state->value != NULL) &&
8418 (ctxt->state->value != ctxt->state->endvalue)) {
8419 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
8420 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008421 }
8422 xmlFree(val);
8423 ctxt->state->value = oldvalue;
8424 ctxt->state->endvalue = oldend;
8425 break;
8426 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008427 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008428 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8429 if (ret != 0) {
8430 break;
8431 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008432 /* no break on purpose */
8433 case XML_RELAXNG_ZEROORMORE: {
8434 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008435
8436 oldflags = ctxt->flags;
8437 ctxt->flags |= FLAGS_IGNORABLE;
8438 cur = ctxt->state->value;
8439 temp = NULL;
8440 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8441 (temp != cur)) {
8442 temp = cur;
8443 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8444 if (ret != 0) {
8445 ctxt->state->value = temp;
8446 ret = 0;
8447 break;
8448 }
8449 cur = ctxt->state->value;
8450 }
8451 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008452 if (ret != 0) {
8453 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8454 xmlRelaxNGDumpValidError(ctxt);
8455 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008456 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008457 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008458 break;
8459 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008460 case XML_RELAXNG_EXCEPT: {
8461 xmlRelaxNGDefinePtr list;
8462
8463 list = define->content;
8464 while (list != NULL) {
8465 ret = xmlRelaxNGValidateValue(ctxt, list);
8466 if (ret == 0) {
8467 ret = -1;
8468 break;
8469 } else
8470 ret = 0;
8471 list = list->next;
8472 }
8473 break;
8474 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008475 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008476 case XML_RELAXNG_GROUP: {
8477 xmlRelaxNGDefinePtr list;
8478
8479 list = define->content;
8480 while (list != NULL) {
8481 ret = xmlRelaxNGValidateValue(ctxt, list);
8482 if (ret != 0) {
8483 ret = -1;
8484 break;
8485 } else
8486 ret = 0;
8487 list = list->next;
8488 }
Daniel Veillardd4310742003-02-18 21:12:46 +00008489 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008490 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008491 case XML_RELAXNG_REF:
8492 case XML_RELAXNG_PARENTREF:
8493 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8494 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008495 default:
8496 TODO
8497 ret = -1;
8498 }
8499 return(ret);
8500}
8501
8502/**
8503 * xmlRelaxNGValidateValueContent:
8504 * @ctxt: a Relax-NG validation context
8505 * @defines: the list of definitions to verify
8506 *
8507 * Validate the given definitions for the current value
8508 *
8509 * Returns 0 if the validation succeeded or an error code.
8510 */
8511static int
8512xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8513 xmlRelaxNGDefinePtr defines) {
8514 int ret = 0;
8515
8516 while (defines != NULL) {
8517 ret = xmlRelaxNGValidateValue(ctxt, defines);
8518 if (ret != 0)
8519 break;
8520 defines = defines->next;
8521 }
8522 return(ret);
8523}
8524
8525/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008526 * xmlRelaxNGAttributeMatch:
8527 * @ctxt: a Relax-NG validation context
8528 * @define: the definition to check
8529 * @prop: the attribute
8530 *
8531 * Check if the attribute matches the definition nameClass
8532 *
8533 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8534 */
8535static int
8536xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8537 xmlRelaxNGDefinePtr define,
8538 xmlAttrPtr prop) {
8539 int ret;
8540
8541 if (define->name != NULL) {
8542 if (!xmlStrEqual(define->name, prop->name))
8543 return(0);
8544 }
8545 if (define->ns != NULL) {
8546 if (define->ns[0] == 0) {
8547 if (prop->ns != NULL)
8548 return(0);
8549 } else {
8550 if ((prop->ns == NULL) ||
8551 (!xmlStrEqual(define->ns, prop->ns->href)))
8552 return(0);
8553 }
8554 }
8555 if (define->nameClass == NULL)
8556 return(1);
8557 define = define->nameClass;
8558 if (define->type == XML_RELAXNG_EXCEPT) {
8559 xmlRelaxNGDefinePtr list;
8560
8561 list = define->content;
8562 while (list != NULL) {
8563 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8564 if (ret == 1)
8565 return(0);
8566 if (ret < 0)
8567 return(ret);
8568 list = list->next;
8569 }
8570 } else {
8571 TODO
8572 }
8573 return(1);
8574}
8575
8576/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008577 * xmlRelaxNGValidateAttribute:
8578 * @ctxt: a Relax-NG validation context
8579 * @define: the definition to verify
8580 *
8581 * Validate the given attribute definition for that node
8582 *
8583 * Returns 0 if the validation succeeded or an error code.
8584 */
8585static int
8586xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8587 xmlRelaxNGDefinePtr define) {
8588 int ret = 0, i;
8589 xmlChar *value, *oldvalue;
8590 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008591 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008592
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008593 if (ctxt->state->nbAttrLeft <= 0)
8594 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008595 if (define->name != NULL) {
8596 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8597 tmp = ctxt->state->attrs[i];
8598 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8599 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8600 (tmp->ns == NULL)) ||
8601 ((tmp->ns != NULL) &&
8602 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8603 prop = tmp;
8604 break;
8605 }
8606 }
8607 }
8608 if (prop != NULL) {
8609 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8610 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008611 oldseq = ctxt->state->seq;
8612 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008613 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00008614 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008615 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008616 if (ctxt->state->value != NULL)
8617 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008618 if (value != NULL)
8619 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008620 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008621 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008622 if (ret == 0) {
8623 /*
8624 * flag the attribute as processed
8625 */
8626 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008627 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008628 }
8629 } else {
8630 ret = -1;
8631 }
8632#ifdef DEBUG
8633 xmlGenericError(xmlGenericErrorContext,
8634 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8635#endif
8636 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008637 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8638 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00008639 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00008640 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008641 prop = tmp;
8642 break;
8643 }
8644 }
8645 if (prop != NULL) {
8646 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8647 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008648 oldseq = ctxt->state->seq;
8649 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008650 ctxt->state->value = value;
8651 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008652 if (ctxt->state->value != NULL)
8653 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008654 if (value != NULL)
8655 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008656 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008657 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008658 if (ret == 0) {
8659 /*
8660 * flag the attribute as processed
8661 */
8662 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008663 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008664 }
8665 } else {
8666 ret = -1;
8667 }
8668#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00008669 if (define->ns != NULL) {
8670 xmlGenericError(xmlGenericErrorContext,
8671 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8672 define->ns, ret);
8673 } else {
8674 xmlGenericError(xmlGenericErrorContext,
8675 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8676 ret);
8677 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008678#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008679 }
8680
8681 return(ret);
8682}
8683
8684/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008685 * xmlRelaxNGValidateAttributeList:
8686 * @ctxt: a Relax-NG validation context
8687 * @define: the list of definition to verify
8688 *
8689 * Validate the given node against the list of attribute definitions
8690 *
8691 * Returns 0 if the validation succeeded or an error code.
8692 */
8693static int
8694xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8695 xmlRelaxNGDefinePtr defines) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00008696 int ret = 0, res;
8697 int needmore = 0;
8698 xmlRelaxNGDefinePtr cur;
8699
8700 cur = defines;
8701 while (cur != NULL) {
8702 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
8703 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8704 ret = -1;
8705 } else
8706 needmore = 1;
8707 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008708 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008709 if (!needmore)
8710 return(ret);
8711 cur = defines;
8712 while (cur != NULL) {
8713 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
8714 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8715 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8716 if (res < 0)
8717 ret = -1;
8718 } else {
8719 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8720 return(-1);
8721 }
8722 if (res == -1) /* continues on -2 */
8723 break;
8724 }
8725 cur = cur->next;
8726 }
8727
Daniel Veillardfd573f12003-03-16 17:52:32 +00008728 return(ret);
8729}
8730
8731/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008732 * xmlRelaxNGNodeMatchesList:
8733 * @node: the node
8734 * @list: a NULL terminated array of definitions
8735 *
8736 * Check if a node can be matched by one of the definitions
8737 *
8738 * Returns 1 if matches 0 otherwise
8739 */
8740static int
8741xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8742 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008743 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008744
8745 if ((node == NULL) || (list == NULL))
8746 return(0);
8747
8748 cur = list[i++];
8749 while (cur != NULL) {
8750 if ((node->type == XML_ELEMENT_NODE) &&
8751 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008752 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8753 if (tmp == 1)
8754 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008755 } else if (((node->type == XML_TEXT_NODE) ||
8756 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008757 (cur->type == XML_RELAXNG_TEXT)) {
8758 return(1);
8759 }
8760 cur = list[i++];
8761 }
8762 return(0);
8763}
8764
8765/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008766 * xmlRelaxNGValidateInterleave:
8767 * @ctxt: a Relax-NG validation context
8768 * @define: the definition to verify
8769 *
8770 * Validate an interleave definition for a node.
8771 *
8772 * Returns 0 if the validation succeeded or an error code.
8773 */
8774static int
8775xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
8776 xmlRelaxNGDefinePtr define) {
8777 int ret = 0, i, nbgroups, left;
8778 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008779 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008780
8781 xmlRelaxNGValidStatePtr oldstate;
8782 xmlRelaxNGPartitionPtr partitions;
8783 xmlRelaxNGInterleaveGroupPtr group = NULL;
8784 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8785 xmlNodePtr *list = NULL, *lasts = NULL;
8786
8787 if (define->data != NULL) {
8788 partitions = (xmlRelaxNGPartitionPtr) define->data;
8789 nbgroups = partitions->nbgroups;
8790 left = nbgroups;
8791 } else {
8792 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8793 return(-1);
8794 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008795 /*
8796 * Optimizations for MIXED
8797 */
8798 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00008799 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008800 ctxt->flags |= FLAGS_MIXED_CONTENT;
8801 if (nbgroups == 2) {
8802 /*
8803 * this is a pure <mixed> case
8804 */
8805 if (ctxt->state != NULL)
8806 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8807 ctxt->state->seq);
8808 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8809 ret = xmlRelaxNGValidateDefinition(ctxt,
8810 partitions->groups[1]->rule);
8811 else
8812 ret = xmlRelaxNGValidateDefinition(ctxt,
8813 partitions->groups[0]->rule);
8814 if (ret == 0) {
8815 if (ctxt->state != NULL)
8816 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8817 ctxt->state->seq);
8818 }
8819 ctxt->flags = oldflags;
8820 return(ret);
8821 }
8822 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008823
8824 /*
8825 * Build arrays to store the first and last node of the chain
8826 * pertaining to each group
8827 */
8828 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8829 if (list == NULL) {
8830 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8831 return(-1);
8832 }
8833 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8834 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8835 if (lasts == NULL) {
8836 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8837 return(-1);
8838 }
8839 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8840
8841 /*
8842 * Walk the sequence of children finding the right group and
8843 * sorting them in sequences.
8844 */
8845 cur = ctxt->state->seq;
8846 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8847 start = cur;
8848 while (cur != NULL) {
8849 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008850 if ((partitions->triage != NULL) &&
8851 (partitions->flags & IS_DETERMINIST)) {
8852 void *tmp = NULL;
8853
8854 if ((cur->type == XML_TEXT_NODE) ||
8855 (cur->type == XML_CDATA_SECTION_NODE)) {
8856 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8857 NULL);
8858 } else if (cur->type == XML_ELEMENT_NODE) {
8859 if (cur->ns != NULL) {
8860 tmp = xmlHashLookup2(partitions->triage, cur->name,
8861 cur->ns->href);
8862 if (tmp == NULL)
8863 tmp = xmlHashLookup2(partitions->triage,
8864 BAD_CAST "#any", cur->ns->href);
8865 } else
8866 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
8867 if (tmp == NULL)
8868 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
8869 NULL);
8870 }
8871
8872 if (tmp == NULL) {
8873 i = nbgroups;
8874 } else {
8875 i = ((long) tmp) - 1;
8876 if (partitions->flags & IS_NEEDCHECK) {
8877 group = partitions->groups[i];
8878 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
8879 i = nbgroups;
8880 }
8881 }
8882 } else {
8883 for (i = 0;i < nbgroups;i++) {
8884 group = partitions->groups[i];
8885 if (group == NULL)
8886 continue;
8887 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
8888 break;
8889 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008890 }
8891 /*
8892 * We break as soon as an element not matched is found
8893 */
8894 if (i >= nbgroups) {
8895 break;
8896 }
8897 if (lasts[i] != NULL) {
8898 lasts[i]->next = cur;
8899 lasts[i] = cur;
8900 } else {
8901 list[i] = cur;
8902 lasts[i] = cur;
8903 }
8904 if (cur->next != NULL)
8905 lastchg = cur->next;
8906 else
8907 lastchg = cur;
8908 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
8909 }
8910 if (ret != 0) {
8911 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8912 ret = -1;
8913 goto done;
8914 }
8915 lastelem = cur;
8916 oldstate = ctxt->state;
8917 for (i = 0;i < nbgroups;i++) {
8918 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
8919 group = partitions->groups[i];
8920 if (lasts[i] != NULL) {
8921 last = lasts[i]->next;
8922 lasts[i]->next = NULL;
8923 }
8924 ctxt->state->seq = list[i];
8925 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
8926 if (ret != 0)
8927 break;
8928 if (ctxt->state != NULL) {
8929 cur = ctxt->state->seq;
8930 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00008931 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008932 oldstate = ctxt->state;
8933 ctxt->state = NULL;
8934 if (cur != NULL) {
8935 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8936 ret = -1;
8937 ctxt->state = oldstate;
8938 goto done;
8939 }
8940 } else if (ctxt->states != NULL) {
8941 int j;
8942 int found = 0;
8943
8944 for (j = 0;j < ctxt->states->nbState;j++) {
8945 cur = ctxt->states->tabState[j]->seq;
8946 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8947 if (cur == NULL) {
8948 found = 1;
8949 break;
8950 }
8951 }
8952 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008953 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008954 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
8955 }
8956 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008957 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008958 }
8959 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8960 ctxt->states = NULL;
8961 if (found == 0) {
8962 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8963 ret = -1;
8964 ctxt->state = oldstate;
8965 goto done;
8966 }
8967 } else {
8968 ret = -1;
8969 break;
8970 }
8971 if (lasts[i] != NULL) {
8972 lasts[i]->next = last;
8973 }
8974 }
8975 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008976 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008977 ctxt->state = oldstate;
8978 ctxt->state->seq = lastelem;
8979 if (ret != 0) {
8980 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8981 ret = -1;
8982 goto done;
8983 }
8984
8985done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008986 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008987 /*
8988 * builds the next links chain from the prev one
8989 */
8990 cur = lastchg;
8991 while (cur != NULL) {
8992 if ((cur == start) || (cur->prev == NULL))
8993 break;
8994 cur->prev->next = cur;
8995 cur = cur->prev;
8996 }
8997 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008998 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008999 }
9000
9001 xmlFree(list);
9002 xmlFree(lasts);
9003 return(ret);
9004}
9005
9006/**
9007 * xmlRelaxNGValidateDefinitionList:
9008 * @ctxt: a Relax-NG validation context
9009 * @define: the list of definition to verify
9010 *
9011 * Validate the given node content against the (list) of definitions
9012 *
9013 * Returns 0 if the validation succeeded or an error code.
9014 */
9015static int
9016xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9017 xmlRelaxNGDefinePtr defines) {
9018 int ret = 0, res;
9019
9020
Daniel Veillard952379b2003-03-17 15:37:12 +00009021 if (defines == NULL) {
9022 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
9023 return(-1);
9024 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009025 while (defines != NULL) {
9026 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9027 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9028 if (res < 0)
9029 ret = -1;
9030 } else {
9031 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9032 return(-1);
9033 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009034 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00009035 break;
9036 defines = defines->next;
9037 }
9038
9039 return(ret);
9040}
9041
9042/**
9043 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009044 * @ctxt: a Relax-NG validation context
9045 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009046 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009047 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009048 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009049 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009050 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009051 */
9052static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009053xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9054 xmlRelaxNGDefinePtr define,
9055 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00009056 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009057
Daniel Veillardfd573f12003-03-16 17:52:32 +00009058 if (define->name != NULL) {
9059 if (!xmlStrEqual(elem->name, define->name)) {
9060 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9061 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009062 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009063 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009064 if ((define->ns != NULL) && (define->ns[0] != 0)) {
9065 if (elem->ns == NULL) {
9066 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
9067 elem->name);
9068 return(0);
9069 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9070 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9071 elem->name, define->ns);
9072 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009073 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009074 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9075 (define->name == NULL)) {
9076 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9077 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009078 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009079 } else if ((elem->ns != NULL) && (define->name != NULL)) {
9080 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9081 define->name);
9082 return(0);
9083 }
9084
9085 if (define->nameClass == NULL)
9086 return(1);
9087
9088 define = define->nameClass;
9089 if (define->type == XML_RELAXNG_EXCEPT) {
9090 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009091 if (ctxt != NULL) {
9092 oldflags = ctxt->flags;
9093 ctxt->flags |= FLAGS_IGNORABLE;
9094 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009095
9096 list = define->content;
9097 while (list != NULL) {
9098 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9099 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009100 if (ctxt != NULL)
9101 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009102 return(0);
9103 }
9104 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009105 if (ctxt != NULL)
9106 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009107 return(ret);
9108 }
9109 list = list->next;
9110 }
9111 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009112 if (ctxt != NULL) {
9113 ctxt->flags = oldflags;
9114 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009115 } else if (define->type == XML_RELAXNG_CHOICE) {
9116 xmlRelaxNGDefinePtr list;
9117
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009118 if (ctxt != NULL) {
9119 oldflags = ctxt->flags;
9120 ctxt->flags |= FLAGS_IGNORABLE;
9121 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009122
9123 list = define->nameClass;
9124 while (list != NULL) {
9125 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9126 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009127 if (ctxt != NULL)
9128 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009129 return(1);
9130 }
9131 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009132 if (ctxt != NULL)
9133 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009134 return(ret);
9135 }
9136 list = list->next;
9137 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009138 if (ctxt != NULL) {
9139 if (ret != 0) {
9140 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9141 xmlRelaxNGDumpValidError(ctxt);
9142 } else {
9143 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
9144 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009145 }
9146 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009147 if (ctxt != NULL) {
9148 ctxt->flags = oldflags;
9149 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009150 } else {
9151 TODO
9152 ret = -1;
9153 }
9154 return(ret);
9155}
9156
9157/**
9158 * xmlRelaxNGValidateElementEnd:
9159 * @ctxt: a Relax-NG validation context
9160 *
9161 * Validate the end of the element, implements check that
9162 * there is nothing left not consumed in the element content
9163 * or in the attribute list.
9164 *
9165 * Returns 0 if the validation succeeded or an error code.
9166 */
9167static int
9168xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
9169 int ret = 0, i;
9170 xmlRelaxNGValidStatePtr state;
9171
9172 state = ctxt->state;
9173 if (state->seq != NULL) {
9174 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9175 if (state->seq != NULL) {
9176 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9177 state->node->name, state->seq->name);
9178 ret = -1;
9179 }
9180 }
9181 for (i = 0;i < state->nbAttrs;i++) {
9182 if (state->attrs[i] != NULL) {
9183 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9184 state->attrs[i]->name, state->node->name);
9185 ret = -1;
9186 }
9187 }
9188 return(ret);
9189}
9190
9191/**
9192 * xmlRelaxNGValidateState:
9193 * @ctxt: a Relax-NG validation context
9194 * @define: the definition to verify
9195 *
9196 * Validate the current state against the definition
9197 *
9198 * Returns 0 if the validation succeeded or an error code.
9199 */
9200static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009201xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9202 xmlRelaxNGDefinePtr define)
9203{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009204 xmlNodePtr node;
9205 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009206 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009207
9208 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009209 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9210 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009211 }
9212
9213 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009214 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009215 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009216 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009217 }
9218#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009219 for (i = 0; i < ctxt->depth; i++)
9220 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009221 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009222 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009223 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009224 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009225 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009226 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009227 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009228 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009229#endif
9230 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009231 switch (define->type) {
9232 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009233 node = xmlRelaxNGSkipIgnored(ctxt, node);
9234 ret = 0;
9235 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009236 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009237 ret = -1;
9238 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009239 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009240 while ((node != NULL) &&
9241 ((node->type == XML_TEXT_NODE) ||
9242 (node->type == XML_COMMENT_NODE) ||
9243 (node->type == XML_PI_NODE) ||
9244 (node->type == XML_CDATA_SECTION_NODE)))
9245 node = node->next;
9246 ctxt->state->seq = node;
9247 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009248 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009249 errNr = ctxt->errNr;
9250 node = xmlRelaxNGSkipIgnored(ctxt, node);
9251 if (node == NULL) {
9252 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9253 ret = -1;
9254 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9255 xmlRelaxNGDumpValidError(ctxt);
9256 break;
9257 }
9258 if (node->type != XML_ELEMENT_NODE) {
9259 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9260 ret = -1;
9261 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9262 xmlRelaxNGDumpValidError(ctxt);
9263 break;
9264 }
9265 /*
9266 * This node was already validated successfully against
9267 * this definition.
9268 */
9269 if (node->_private == define) {
9270 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9271 if (ctxt->errNr > errNr)
9272 xmlRelaxNGPopErrors(ctxt, errNr);
9273 if (ctxt->errNr != 0) {
9274 while ((ctxt->err != NULL) &&
9275 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9276 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9277 ||
9278 ((ctxt->err->err ==
9279 XML_RELAXNG_ERR_ELEMEXTRANS)
9280 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9281 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9282 || (ctxt->err->err ==
9283 XML_RELAXNG_ERR_NOTELEM)))
9284 xmlRelaxNGValidErrorPop(ctxt);
9285 }
9286 break;
9287 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009288
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009289 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9290 if (ret <= 0) {
9291 ret = -1;
9292 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9293 xmlRelaxNGDumpValidError(ctxt);
9294 break;
9295 }
9296 ret = 0;
9297 if (ctxt->errNr != 0) {
9298 if (ctxt->errNr > errNr)
9299 xmlRelaxNGPopErrors(ctxt, errNr);
9300 while ((ctxt->err != NULL) &&
9301 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9302 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9303 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9304 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9305 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9306 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9307 xmlRelaxNGValidErrorPop(ctxt);
9308 }
9309 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009310
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009311 oldflags = ctxt->flags;
9312 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9313 ctxt->flags -= FLAGS_MIXED_CONTENT;
9314 }
9315 state = xmlRelaxNGNewValidState(ctxt, node);
9316 if (state == NULL) {
9317 ret = -1;
9318 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9319 xmlRelaxNGDumpValidError(ctxt);
9320 break;
9321 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009322
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009323 oldstate = ctxt->state;
9324 ctxt->state = state;
9325 if (define->attrs != NULL) {
9326 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9327 if (tmp != 0) {
9328 ret = -1;
9329 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9330 }
9331 }
9332 if (define->contModel != NULL) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009333 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9334 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9335 xmlNodePtr nseq;
9336
9337 nstate = xmlRelaxNGNewValidState(ctxt, node);
9338 ctxt->state = nstate;
9339 ctxt->states = NULL;
9340
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009341 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9342 define->contModel,
9343 ctxt->state->seq);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009344 nseq = ctxt->state->seq;
9345 ctxt->state = tmpstate;
9346 ctxt->states = tmpstates;
9347 xmlRelaxNGFreeValidState(ctxt, nstate);
9348
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009349#ifdef DEBUG_COMPILE
9350 xmlGenericError(xmlGenericErrorContext,
9351 "Validating content of '%s' : %d\n", define->name, tmp);
9352#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009353 if (tmp != 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009354 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009355
9356 if (ctxt->states != NULL) {
9357 tmp = -1;
9358
9359 ctxt->flags |= FLAGS_IGNORABLE;
9360
9361 for (i = 0; i < ctxt->states->nbState; i++) {
9362 state = ctxt->states->tabState[i];
9363 ctxt->state = state;
9364 ctxt->state->seq = nseq;
9365
9366 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9367 tmp = 0;
9368 xmlRelaxNGFreeValidState(ctxt, state);
9369 }
9370 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9371 ctxt->flags = oldflags;
9372 ctxt->states = NULL;
9373 if ((ret == 0) && (tmp == -1))
9374 ret = -1;
9375 } else {
9376 state = ctxt->state;
9377 ctxt->state->seq = nseq;
9378 if (ret == 0)
9379 ret = xmlRelaxNGValidateElementEnd(ctxt);
9380 xmlRelaxNGFreeValidState(ctxt, state);
9381 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009382 } else {
9383 if (define->content != NULL) {
9384 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9385 define->content);
9386 if (tmp != 0) {
9387 ret = -1;
9388 if (ctxt->state == NULL) {
9389 ctxt->state = oldstate;
9390 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9391 node->name);
9392 ctxt->state = NULL;
9393 } else {
9394 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9395 node->name);
9396 }
9397
9398 }
9399 }
9400 if (ctxt->states != NULL) {
9401 tmp = -1;
9402
9403 ctxt->flags |= FLAGS_IGNORABLE;
9404
9405 for (i = 0; i < ctxt->states->nbState; i++) {
9406 state = ctxt->states->tabState[i];
9407 ctxt->state = state;
9408
9409 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9410 tmp = 0;
9411 xmlRelaxNGFreeValidState(ctxt, state);
9412 }
9413 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9414 ctxt->flags = oldflags;
9415 ctxt->states = NULL;
9416 if ((ret == 0) && (tmp == -1))
9417 ret = -1;
9418 } else {
9419 state = ctxt->state;
9420 if (ret == 0)
9421 ret = xmlRelaxNGValidateElementEnd(ctxt);
9422 xmlRelaxNGFreeValidState(ctxt, state);
9423 }
9424 }
9425 if (ret == 0) {
9426 node->_private = define;
9427 }
9428 ctxt->flags = oldflags;
9429 ctxt->state = oldstate;
9430 if (oldstate != NULL)
9431 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9432 if (ret != 0) {
9433 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9434 xmlRelaxNGDumpValidError(ctxt);
9435 ret = 0;
9436 } else {
9437 ret = -2;
9438 }
9439 } else {
9440 if (ctxt->errNr > errNr)
9441 xmlRelaxNGPopErrors(ctxt, errNr);
9442 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009443
9444#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009445 xmlGenericError(xmlGenericErrorContext,
9446 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9447 node->name, ret);
9448 if (oldstate == NULL)
9449 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9450 else if (oldstate->seq == NULL)
9451 xmlGenericError(xmlGenericErrorContext, ": done\n");
9452 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9453 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9454 oldstate->seq->name);
9455 else
9456 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9457 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009458#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009459 break;
9460 case XML_RELAXNG_OPTIONAL:{
9461 errNr = ctxt->errNr;
9462 oldflags = ctxt->flags;
9463 ctxt->flags |= FLAGS_IGNORABLE;
9464 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9465 ret =
9466 xmlRelaxNGValidateDefinitionList(ctxt,
9467 define->content);
9468 if (ret != 0) {
9469 if (ctxt->state != NULL)
9470 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9471 ctxt->state = oldstate;
9472 ctxt->flags = oldflags;
9473 ret = 0;
9474 if (ctxt->errNr > errNr)
9475 xmlRelaxNGPopErrors(ctxt, errNr);
9476 break;
9477 }
9478 if (ctxt->states != NULL) {
9479 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9480 } else {
9481 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9482 if (ctxt->states == NULL) {
9483 xmlRelaxNGFreeValidState(ctxt, oldstate);
9484 ctxt->flags = oldflags;
9485 ret = -1;
9486 if (ctxt->errNr > errNr)
9487 xmlRelaxNGPopErrors(ctxt, errNr);
9488 break;
9489 }
9490 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9491 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9492 ctxt->state = NULL;
9493 }
9494 ctxt->flags = oldflags;
9495 ret = 0;
9496 if (ctxt->errNr > errNr)
9497 xmlRelaxNGPopErrors(ctxt, errNr);
9498 break;
9499 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009500 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009501 errNr = ctxt->errNr;
9502 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9503 if (ret != 0) {
9504 break;
9505 }
9506 if (ctxt->errNr > errNr)
9507 xmlRelaxNGPopErrors(ctxt, errNr);
9508 /* no break on purpose */
9509 case XML_RELAXNG_ZEROORMORE:{
9510 int progress;
9511 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9512 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009513
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009514 errNr = ctxt->errNr;
9515 res = xmlRelaxNGNewStates(ctxt, 1);
9516 if (res == NULL) {
9517 ret = -1;
9518 break;
9519 }
9520 /*
9521 * All the input states are also exit states
9522 */
9523 if (ctxt->state != NULL) {
9524 xmlRelaxNGAddStates(ctxt, res,
9525 xmlRelaxNGCopyValidState(ctxt,
9526 ctxt->
9527 state));
9528 } else {
9529 for (j = 0; j < ctxt->states->nbState; j++) {
9530 xmlRelaxNGAddStates(ctxt, res,
9531 xmlRelaxNGCopyValidState(ctxt,
9532 ctxt->
9533 states->
9534 tabState
9535 [j]));
9536 }
9537 }
9538 oldflags = ctxt->flags;
9539 ctxt->flags |= FLAGS_IGNORABLE;
9540 do {
9541 progress = 0;
9542 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009543
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009544 if (ctxt->states != NULL) {
9545 states = ctxt->states;
9546 for (i = 0; i < states->nbState; i++) {
9547 ctxt->state = states->tabState[i];
9548 ctxt->states = NULL;
9549 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9550 define->
9551 content);
9552 if (ret == 0) {
9553 if (ctxt->state != NULL) {
9554 tmp = xmlRelaxNGAddStates(ctxt, res,
9555 ctxt->state);
9556 ctxt->state = NULL;
9557 if (tmp == 1)
9558 progress = 1;
9559 } else if (ctxt->states != NULL) {
9560 for (j = 0; j < ctxt->states->nbState;
9561 j++) {
9562 tmp =
9563 xmlRelaxNGAddStates(ctxt, res,
9564 ctxt->
9565 states->
9566 tabState
9567 [j]);
9568 if (tmp == 1)
9569 progress = 1;
9570 }
9571 xmlRelaxNGFreeStates(ctxt,
9572 ctxt->states);
9573 ctxt->states = NULL;
9574 }
9575 } else {
9576 if (ctxt->state != NULL) {
9577 xmlRelaxNGFreeValidState(ctxt,
9578 ctxt->state);
9579 ctxt->state = NULL;
9580 }
9581 }
9582 }
9583 } else {
9584 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9585 define->
9586 content);
9587 if (ret != 0) {
9588 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9589 ctxt->state = NULL;
9590 } else {
9591 base = res->nbState;
9592 if (ctxt->state != NULL) {
9593 tmp = xmlRelaxNGAddStates(ctxt, res,
9594 ctxt->state);
9595 ctxt->state = NULL;
9596 if (tmp == 1)
9597 progress = 1;
9598 } else if (ctxt->states != NULL) {
9599 for (j = 0; j < ctxt->states->nbState; j++) {
9600 tmp = xmlRelaxNGAddStates(ctxt, res,
9601 ctxt->
9602 states->
9603 tabState[j]);
9604 if (tmp == 1)
9605 progress = 1;
9606 }
9607 if (states == NULL) {
9608 states = ctxt->states;
9609 } else {
9610 xmlRelaxNGFreeStates(ctxt,
9611 ctxt->states);
9612 }
9613 ctxt->states = NULL;
9614 }
9615 }
9616 }
9617 if (progress) {
9618 /*
9619 * Collect all the new nodes added at that step
9620 * and make them the new node set
9621 */
9622 if (res->nbState - base == 1) {
9623 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9624 res->
9625 tabState
9626 [base]);
9627 } else {
9628 if (states == NULL) {
9629 xmlRelaxNGNewStates(ctxt,
9630 res->nbState - base);
9631 }
9632 states->nbState = 0;
9633 for (i = base; i < res->nbState; i++)
9634 xmlRelaxNGAddStates(ctxt, states,
9635 xmlRelaxNGCopyValidState
9636 (ctxt,
9637 res->tabState[i]));
9638 ctxt->states = states;
9639 }
9640 }
9641 } while (progress == 1);
9642 if (states != NULL) {
9643 xmlRelaxNGFreeStates(ctxt, states);
9644 }
9645 ctxt->states = res;
9646 ctxt->flags = oldflags;
9647 if (ctxt->errNr > errNr)
9648 xmlRelaxNGPopErrors(ctxt, errNr);
9649 ret = 0;
9650 break;
9651 }
9652 case XML_RELAXNG_CHOICE:{
9653 xmlRelaxNGDefinePtr list = NULL;
9654 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009655
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009656 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009657
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009658 errNr = ctxt->errNr;
9659 if ((define->dflags & IS_TRIABLE)
9660 && (define->data != NULL)) {
9661 xmlHashTablePtr triage =
9662 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +00009663
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009664 /*
9665 * Something we can optimize cleanly there is only one
9666 * possble branch out !
9667 */
9668 if (node == NULL) {
9669 ret = -1;
9670 break;
9671 }
9672 if ((node->type == XML_TEXT_NODE) ||
9673 (node->type == XML_CDATA_SECTION_NODE)) {
9674 list =
9675 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9676 } else if (node->type == XML_ELEMENT_NODE) {
9677 if (node->ns != NULL) {
9678 list = xmlHashLookup2(triage, node->name,
9679 node->ns->href);
9680 if (list == NULL)
9681 list =
9682 xmlHashLookup2(triage, BAD_CAST "#any",
9683 node->ns->href);
9684 } else
9685 list =
9686 xmlHashLookup2(triage, node->name, NULL);
9687 if (list == NULL)
9688 list =
9689 xmlHashLookup2(triage, BAD_CAST "#any",
9690 NULL);
9691 }
9692 if (list == NULL) {
9693 ret = -1;
9694 break;
9695 }
9696 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9697 if (ret == 0) {
9698 }
9699 break;
9700 }
Daniel Veillarde063f482003-03-21 16:53:17 +00009701
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009702 list = define->content;
9703 oldflags = ctxt->flags;
9704 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009705
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009706 while (list != NULL) {
9707 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9708 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9709 if (ret == 0) {
9710 if (states == NULL) {
9711 states = xmlRelaxNGNewStates(ctxt, 1);
9712 }
9713 if (ctxt->state != NULL) {
9714 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9715 } else if (ctxt->states != NULL) {
9716 for (i = 0; i < ctxt->states->nbState; i++) {
9717 xmlRelaxNGAddStates(ctxt, states,
9718 ctxt->states->
9719 tabState[i]);
9720 }
9721 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9722 ctxt->states = NULL;
9723 }
9724 } else {
9725 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9726 }
9727 ctxt->state = oldstate;
9728 list = list->next;
9729 }
9730 if (states != NULL) {
9731 xmlRelaxNGFreeValidState(ctxt, oldstate);
9732 ctxt->states = states;
9733 ctxt->state = NULL;
9734 ret = 0;
9735 } else {
9736 ctxt->states = NULL;
9737 }
9738 ctxt->flags = oldflags;
9739 if (ret != 0) {
9740 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9741 xmlRelaxNGDumpValidError(ctxt);
9742 }
9743 } else {
9744 if (ctxt->errNr > errNr)
9745 xmlRelaxNGPopErrors(ctxt, errNr);
9746 }
9747 break;
9748 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009749 case XML_RELAXNG_DEF:
9750 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009751 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9752 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009753 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009754 ret = xmlRelaxNGValidateInterleave(ctxt, define);
9755 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009756 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009757 ret = xmlRelaxNGValidateAttribute(ctxt, define);
9758 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +00009759 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009760 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00009761 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009762 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +00009763 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009764 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9765 break;
9766 case XML_RELAXNG_DATATYPE:{
9767 xmlNodePtr child;
9768 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009769
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009770 child = node;
9771 while (child != NULL) {
9772 if (child->type == XML_ELEMENT_NODE) {
9773 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9774 node->parent->name);
9775 ret = -1;
9776 break;
9777 } else if ((child->type == XML_TEXT_NODE) ||
9778 (child->type == XML_CDATA_SECTION_NODE)) {
9779 content = xmlStrcat(content, child->content);
9780 }
9781 /* TODO: handle entities ... */
9782 child = child->next;
9783 }
9784 if (ret == -1) {
9785 if (content != NULL)
9786 xmlFree(content);
9787 break;
9788 }
9789 if (content == NULL) {
9790 content = xmlStrdup(BAD_CAST "");
9791 if (content == NULL) {
9792 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9793 ret = -1;
9794 break;
9795 }
9796 }
9797 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9798 ctxt->state->seq);
9799 if (ret == -1) {
9800 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9801 } else if (ret == 0) {
9802 ctxt->state->seq = NULL;
9803 }
9804 if (content != NULL)
9805 xmlFree(content);
9806 break;
9807 }
9808 case XML_RELAXNG_VALUE:{
9809 xmlChar *content = NULL;
9810 xmlChar *oldvalue;
9811 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009812
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009813 child = node;
9814 while (child != NULL) {
9815 if (child->type == XML_ELEMENT_NODE) {
9816 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9817 node->parent->name);
9818 ret = -1;
9819 break;
9820 } else if ((child->type == XML_TEXT_NODE) ||
9821 (child->type == XML_CDATA_SECTION_NODE)) {
9822 content = xmlStrcat(content, child->content);
9823 }
9824 /* TODO: handle entities ... */
9825 child = child->next;
9826 }
9827 if (ret == -1) {
9828 if (content != NULL)
9829 xmlFree(content);
9830 break;
9831 }
9832 if (content == NULL) {
9833 content = xmlStrdup(BAD_CAST "");
9834 if (content == NULL) {
9835 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9836 ret = -1;
9837 break;
9838 }
9839 }
9840 oldvalue = ctxt->state->value;
9841 ctxt->state->value = content;
9842 ret = xmlRelaxNGValidateValue(ctxt, define);
9843 ctxt->state->value = oldvalue;
9844 if (ret == -1) {
9845 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9846 } else if (ret == 0) {
9847 ctxt->state->seq = NULL;
9848 }
9849 if (content != NULL)
9850 xmlFree(content);
9851 break;
9852 }
9853 case XML_RELAXNG_LIST:{
9854 xmlChar *content;
9855 xmlNodePtr child;
9856 xmlChar *oldvalue, *oldendvalue;
9857 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009858
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009859 /*
9860 * Make sure it's only text nodes
9861 */
9862
9863 content = NULL;
9864 child = node;
9865 while (child != NULL) {
9866 if (child->type == XML_ELEMENT_NODE) {
9867 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
9868 node->parent->name);
9869 ret = -1;
9870 break;
9871 } else if ((child->type == XML_TEXT_NODE) ||
9872 (child->type == XML_CDATA_SECTION_NODE)) {
9873 content = xmlStrcat(content, child->content);
9874 }
9875 /* TODO: handle entities ... */
9876 child = child->next;
9877 }
9878 if (ret == -1) {
9879 if (content != NULL)
9880 xmlFree(content);
9881 break;
9882 }
9883 if (content == NULL) {
9884 content = xmlStrdup(BAD_CAST "");
9885 if (content == NULL) {
9886 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9887 ret = -1;
9888 break;
9889 }
9890 }
9891 len = xmlStrlen(content);
9892 oldvalue = ctxt->state->value;
9893 oldendvalue = ctxt->state->endvalue;
9894 ctxt->state->value = content;
9895 ctxt->state->endvalue = content + len;
9896 ret = xmlRelaxNGValidateValue(ctxt, define);
9897 ctxt->state->value = oldvalue;
9898 ctxt->state->endvalue = oldendvalue;
9899 if (ret == -1) {
9900 VALID_ERR(XML_RELAXNG_ERR_LIST);
9901 } else if ((ret == 0) && (node != NULL)) {
9902 ctxt->state->seq = node->next;
9903 }
9904 if (content != NULL)
9905 xmlFree(content);
9906 break;
9907 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009908 case XML_RELAXNG_EXCEPT:
9909 case XML_RELAXNG_PARAM:
9910 TODO ret = -1;
9911 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009912 }
9913 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009914#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009915 for (i = 0; i < ctxt->depth; i++)
9916 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009917 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009918 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009919 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009920 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009921 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009922 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009923 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009924 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009925#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009926 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009927}
9928
9929/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009930 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009931 * @ctxt: a Relax-NG validation context
9932 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009933 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009934 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009935 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009936 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009937 */
9938static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009939xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
9940 xmlRelaxNGDefinePtr define) {
9941 xmlRelaxNGStatesPtr states, res;
9942 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009943
Daniel Veillardfd573f12003-03-16 17:52:32 +00009944 /*
9945 * We should NOT have both ctxt->state and ctxt->states
9946 */
9947 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9948 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009949 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009950 ctxt->state = NULL;
9951 }
9952
9953 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
9954 if (ctxt->states != NULL) {
9955 ctxt->state = ctxt->states->tabState[0];
9956 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9957 ctxt->states = NULL;
9958 }
9959 ret = xmlRelaxNGValidateState(ctxt, define);
9960 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9961 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009962 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009963 ctxt->state = NULL;
9964 }
9965 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
9966 ctxt->state = ctxt->states->tabState[0];
9967 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9968 ctxt->states = NULL;
9969 }
9970 return(ret);
9971 }
9972
9973 states = ctxt->states;
9974 ctxt->states = NULL;
9975 res = NULL;
9976 j = 0;
9977 oldflags = ctxt->flags;
9978 ctxt->flags |= FLAGS_IGNORABLE;
9979 for (i = 0;i < states->nbState;i++) {
9980 ctxt->state = states->tabState[i];
9981 ctxt->states = NULL;
9982 ret = xmlRelaxNGValidateState(ctxt, define);
9983 /*
9984 * We should NOT have both ctxt->state and ctxt->states
9985 */
9986 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9987 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009988 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009989 ctxt->state = NULL;
9990 }
9991 if (ret == 0) {
9992 if (ctxt->states == NULL) {
9993 if (res != NULL) {
9994 /* add the state to the container */
9995 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
9996 ctxt->state = NULL;
9997 } else {
9998 /* add the state directly in states */
9999 states->tabState[j++] = ctxt->state;
10000 ctxt->state = NULL;
10001 }
10002 } else {
10003 if (res == NULL) {
10004 /* make it the new container and copy other results */
10005 res = ctxt->states;
10006 ctxt->states = NULL;
10007 for (k = 0;k < j;k++)
10008 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
10009 } else {
10010 /* add all the new results to res and reff the container */
10011 for (k = 0;k < ctxt->states->nbState;k++)
10012 xmlRelaxNGAddStates(ctxt, res,
10013 ctxt->states->tabState[k]);
10014 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10015 ctxt->states = NULL;
10016 }
10017 }
10018 } else {
10019 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010020 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010021 ctxt->state = NULL;
10022 } else if (ctxt->states != NULL) {
10023 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +000010024 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010025 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10026 ctxt->states = NULL;
10027 }
10028 }
10029 }
10030 ctxt->flags = oldflags;
10031 if (res != NULL) {
10032 xmlRelaxNGFreeStates(ctxt, states);
10033 ctxt->states = res;
10034 ret = 0;
10035 } else if (j > 1) {
10036 states->nbState = j;
10037 ctxt->states = states;
10038 ret =0;
10039 } else if (j == 1) {
10040 ctxt->state = states->tabState[0];
10041 xmlRelaxNGFreeStates(ctxt, states);
10042 ret = 0;
10043 } else {
10044 ret = -1;
10045 xmlRelaxNGFreeStates(ctxt, states);
10046 if (ctxt->states != NULL) {
10047 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10048 ctxt->states = NULL;
10049 }
10050 }
10051 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10052 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010053 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010054 ctxt->state = NULL;
10055 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010056 return(ret);
10057}
10058
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010059/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010060 * xmlRelaxNGValidateDocument:
10061 * @ctxt: a Relax-NG validation context
10062 * @doc: the document
10063 *
10064 * Validate the given document
10065 *
10066 * Returns 0 if the validation succeeded or an error code.
10067 */
10068static int
10069xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10070 int ret;
10071 xmlRelaxNGPtr schema;
10072 xmlRelaxNGGrammarPtr grammar;
10073 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010074 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010075
10076 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10077 return(-1);
10078
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010079 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010080 schema = ctxt->schema;
10081 grammar = schema->topgrammar;
10082 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +000010083 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010084 return(-1);
10085 }
10086 state = xmlRelaxNGNewValidState(ctxt, NULL);
10087 ctxt->state = state;
10088 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010089 if ((ctxt->state != NULL) && (state->seq != NULL)) {
10090 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010091 node = state->seq;
10092 node = xmlRelaxNGSkipIgnored(ctxt, node);
10093 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +000010094 if (ret != -1) {
10095 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10096 ret = -1;
10097 }
10098 }
10099 } else if (ctxt->states != NULL) {
10100 int i;
10101 int tmp = -1;
10102
10103 for (i = 0;i < ctxt->states->nbState;i++) {
10104 state = ctxt->states->tabState[i];
10105 node = state->seq;
10106 node = xmlRelaxNGSkipIgnored(ctxt, node);
10107 if (node == NULL)
10108 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +000010109 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010110 }
10111 if (tmp == -1) {
10112 if (ret != -1) {
10113 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10114 ret = -1;
10115 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010116 }
10117 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010118 if (ctxt->state != NULL) {
10119 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10120 ctxt->state = NULL;
10121 }
Daniel Veillard580ced82003-03-21 21:22:48 +000010122 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +000010123 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010124#ifdef DEBUG
10125 else if (ctxt->errNr != 0) {
10126 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
10127 ctxt->errNr);
10128 xmlRelaxNGDumpValidError(ctxt);
10129 }
10130#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010131 if (ctxt->idref == 1) {
10132 xmlValidCtxt vctxt;
10133
10134 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10135 vctxt.valid = 1;
10136 vctxt.error = ctxt->error;
10137 vctxt.warning = ctxt->warning;
10138 vctxt.userData = ctxt->userData;
10139
10140 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10141 ret = -1;
10142 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010143 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10144 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010145
10146 return(ret);
10147}
10148
Daniel Veillardfd573f12003-03-16 17:52:32 +000010149/************************************************************************
10150 * *
10151 * Validation interfaces *
10152 * *
10153 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +000010154/**
10155 * xmlRelaxNGNewValidCtxt:
10156 * @schema: a precompiled XML RelaxNGs
10157 *
10158 * Create an XML RelaxNGs validation context based on the given schema
10159 *
10160 * Returns the validation context or NULL in case of error
10161 */
10162xmlRelaxNGValidCtxtPtr
10163xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
10164 xmlRelaxNGValidCtxtPtr ret;
10165
10166 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10167 if (ret == NULL) {
10168 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +000010169 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010170 return (NULL);
10171 }
10172 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10173 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010174 ret->error = xmlGenericError;
10175 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010176 ret->errNr = 0;
10177 ret->errMax = 0;
10178 ret->err = NULL;
10179 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010180 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010181 ret->states = NULL;
10182 ret->freeState = NULL;
10183 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010184 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010185 return (ret);
10186}
10187
10188/**
10189 * xmlRelaxNGFreeValidCtxt:
10190 * @ctxt: the schema validation context
10191 *
10192 * Free the resources associated to the schema validation context
10193 */
10194void
10195xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010196 int k;
10197
Daniel Veillard6eadf632003-01-23 18:29:16 +000010198 if (ctxt == NULL)
10199 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010200 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +000010201 xmlRelaxNGFreeStates(NULL, ctxt->states);
10202 if (ctxt->freeState != NULL) {
10203 for (k = 0;k < ctxt->freeState->nbState;k++) {
10204 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10205 }
10206 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10207 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010208 if (ctxt->freeStates != NULL) {
10209 for (k = 0;k < ctxt->freeStatesNr;k++) {
10210 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10211 }
10212 xmlFree(ctxt->freeStates);
10213 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010214 if (ctxt->errTab != NULL)
10215 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010216 if (ctxt->elemTab != NULL) {
10217 xmlRegExecCtxtPtr exec;
10218
10219 exec = xmlRelaxNGElemPop(ctxt);
10220 while (exec != NULL) {
10221 xmlRegFreeExecCtxt(exec);
10222 exec = xmlRelaxNGElemPop(ctxt);
10223 }
10224 xmlFree(ctxt->elemTab);
10225 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010226 xmlFree(ctxt);
10227}
10228
10229/**
10230 * xmlRelaxNGSetValidErrors:
10231 * @ctxt: a Relax-NG validation context
10232 * @err: the error function
10233 * @warn: the warning function
10234 * @ctx: the functions context
10235 *
10236 * Set the error and warning callback informations
10237 */
10238void
10239xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10240 xmlRelaxNGValidityErrorFunc err,
10241 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
10242 if (ctxt == NULL)
10243 return;
10244 ctxt->error = err;
10245 ctxt->warning = warn;
10246 ctxt->userData = ctx;
10247}
10248
10249/**
10250 * xmlRelaxNGValidateDoc:
10251 * @ctxt: a Relax-NG validation context
10252 * @doc: a parsed document tree
10253 *
10254 * Validate a document tree in memory.
10255 *
10256 * Returns 0 if the document is valid, a positive error code
10257 * number otherwise and -1 in case of internal or API error.
10258 */
10259int
10260xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10261 int ret;
10262
10263 if ((ctxt == NULL) || (doc == NULL))
10264 return(-1);
10265
10266 ctxt->doc = doc;
10267
10268 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010269 /*
10270 * TODO: build error codes
10271 */
10272 if (ret == -1)
10273 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010274 return(ret);
10275}
10276
10277#endif /* LIBXML_SCHEMAS_ENABLED */
10278