blob: cb3c130c387910139302e95c3b050f8fb88dc3d6 [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/**
3620 * xmlRelaxNGGetElements:
3621 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003622 * @def: the definition definition
3623 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003624 *
3625 * Compute the list of top elements a definition can generate
3626 *
3627 * Returns a list of elements or NULL if none was found.
3628 */
3629static xmlRelaxNGDefinePtr *
3630xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003631 xmlRelaxNGDefinePtr def,
3632 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003633 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003634 int len = 0;
3635 int max = 0;
3636
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003637 /*
3638 * Don't run that check in case of error. Infinite recursion
3639 * becomes possible.
3640 */
3641 if (ctxt->nbErrors != 0)
3642 return(NULL);
3643
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003644 parent = NULL;
3645 cur = def;
3646 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003647 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3648 (cur->type == XML_RELAXNG_TEXT))) ||
3649 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003650 if (ret == NULL) {
3651 max = 10;
3652 ret = (xmlRelaxNGDefinePtr *)
3653 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3654 if (ret == NULL) {
3655 if (ctxt->error != NULL)
3656 ctxt->error(ctxt->userData,
3657 "Out of memory in element search\n");
3658 ctxt->nbErrors++;
3659 return(NULL);
3660 }
3661 } else if (max <= len) {
3662 max *= 2;
3663 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3664 if (ret == NULL) {
3665 if (ctxt->error != NULL)
3666 ctxt->error(ctxt->userData,
3667 "Out of memory in element search\n");
3668 ctxt->nbErrors++;
3669 return(NULL);
3670 }
3671 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003672 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003673 ret[len] = NULL;
3674 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3675 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3676 (cur->type == XML_RELAXNG_GROUP) ||
3677 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003678 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3679 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003680 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003681 (cur->type == XML_RELAXNG_REF) ||
3682 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003683 /*
3684 * Don't go within elements or attributes or string values.
3685 * Just gather the element top list
3686 */
3687 if (cur->content != NULL) {
3688 parent = cur;
3689 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003690 tmp = cur;
3691 while (tmp != NULL) {
3692 tmp->parent = parent;
3693 tmp = tmp->next;
3694 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003695 continue;
3696 }
3697 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003698 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003699 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003700 if (cur->next != NULL) {
3701 cur = cur->next;
3702 continue;
3703 }
3704 do {
3705 cur = cur->parent;
3706 if (cur == NULL) break;
3707 if (cur == def) return(ret);
3708 if (cur->next != NULL) {
3709 cur = cur->next;
3710 break;
3711 }
3712 } while (cur != NULL);
3713 }
3714 return(ret);
3715}
3716
3717/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003718 * xmlRelaxNGCheckChoiceDeterminism:
3719 * @ctxt: a Relax-NG parser context
3720 * @def: the choice definition
3721 *
3722 * Also used to find indeterministic pattern in choice
3723 */
3724static void
3725xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3726 xmlRelaxNGDefinePtr def) {
3727 xmlRelaxNGDefinePtr **list;
3728 xmlRelaxNGDefinePtr cur;
3729 int nbchild = 0, i, j, ret;
3730 int is_nullable = 0;
3731 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003732 xmlHashTablePtr triage = NULL;
3733 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003734
3735 if ((def == NULL) ||
3736 (def->type != XML_RELAXNG_CHOICE))
3737 return;
3738
Daniel Veillarde063f482003-03-21 16:53:17 +00003739 if (def->dflags & IS_PROCESSED)
3740 return;
3741
Daniel Veillardfd573f12003-03-16 17:52:32 +00003742 /*
3743 * Don't run that check in case of error. Infinite recursion
3744 * becomes possible.
3745 */
3746 if (ctxt->nbErrors != 0)
3747 return;
3748
3749 is_nullable = xmlRelaxNGIsNullable(def);
3750
3751 cur = def->content;
3752 while (cur != NULL) {
3753 nbchild++;
3754 cur = cur->next;
3755 }
3756
3757 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3758 sizeof(xmlRelaxNGDefinePtr *));
3759 if (list == NULL) {
3760 if (ctxt->error != NULL)
3761 ctxt->error(ctxt->userData,
3762 "Out of memory in choice computation\n");
3763 ctxt->nbErrors++;
3764 return;
3765 }
3766 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003767 /*
3768 * a bit strong but safe
3769 */
3770 if (is_nullable == 0) {
3771 triage = xmlHashCreate(10);
3772 } else {
3773 is_triable = 0;
3774 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003775 cur = def->content;
3776 while (cur != NULL) {
3777 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003778 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3779 is_triable = 0;
3780 } else if (is_triable == 1) {
3781 xmlRelaxNGDefinePtr *tmp;
3782 int res;
3783
3784 tmp = list[i];
3785 while ((*tmp != NULL) && (is_triable == 1)) {
3786 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3787 res = xmlHashAddEntry2(triage,
3788 BAD_CAST "#text", NULL,
3789 (void *)cur);
3790 if (res != 0)
3791 is_triable = -1;
3792 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3793 ((*tmp)->name != NULL)) {
3794 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3795 res = xmlHashAddEntry2(triage,
3796 (*tmp)->name, NULL,
3797 (void *)cur);
3798 else
3799 res = xmlHashAddEntry2(triage,
3800 (*tmp)->name, (*tmp)->ns,
3801 (void *)cur);
3802 if (res != 0)
3803 is_triable = -1;
3804 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3805 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3806 res = xmlHashAddEntry2(triage,
3807 BAD_CAST "#any", NULL,
3808 (void *)cur);
3809 else
3810 res = xmlHashAddEntry2(triage,
3811 BAD_CAST "#any", (*tmp)->ns,
3812 (void *)cur);
3813 if (res != 0)
3814 is_triable = -1;
3815 } else {
3816 is_triable = -1;
3817 }
3818 tmp++;
3819 }
3820 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003821 i++;
3822 cur = cur->next;
3823 }
3824
3825 for (i = 0;i < nbchild;i++) {
3826 if (list[i] == NULL)
3827 continue;
3828 for (j = 0;j < i;j++) {
3829 if (list[j] == NULL)
3830 continue;
3831 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3832 if (ret == 0) {
3833 is_indeterminist = 1;
3834 }
3835 }
3836 }
3837 for (i = 0;i < nbchild;i++) {
3838 if (list[i] != NULL)
3839 xmlFree(list[i]);
3840 }
3841
3842 xmlFree(list);
3843 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003844 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003845 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003846 if (is_triable == 1) {
3847 def->dflags |= IS_TRIABLE;
3848 def->data = triage;
3849 } else if (triage != NULL) {
3850 xmlHashFree(triage, NULL);
3851 }
3852 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003853}
3854
3855/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003856 * xmlRelaxNGCheckGroupAttrs:
3857 * @ctxt: a Relax-NG parser context
3858 * @def: the group definition
3859 *
3860 * Detects violations of rule 7.3
3861 */
3862static void
3863xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3864 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003865 xmlRelaxNGDefinePtr **list;
3866 xmlRelaxNGDefinePtr cur;
3867 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003868
3869 if ((def == NULL) ||
3870 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003871 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003872 return;
3873
Daniel Veillarde063f482003-03-21 16:53:17 +00003874 if (def->dflags & IS_PROCESSED)
3875 return;
3876
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003877 /*
3878 * Don't run that check in case of error. Infinite recursion
3879 * becomes possible.
3880 */
3881 if (ctxt->nbErrors != 0)
3882 return;
3883
Daniel Veillardfd573f12003-03-16 17:52:32 +00003884 cur = def->attrs;
3885 while (cur != NULL) {
3886 nbchild++;
3887 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003888 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003889 cur = def->content;
3890 while (cur != NULL) {
3891 nbchild++;
3892 cur = cur->next;
3893 }
3894
3895 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3896 sizeof(xmlRelaxNGDefinePtr *));
3897 if (list == NULL) {
3898 if (ctxt->error != NULL)
3899 ctxt->error(ctxt->userData,
3900 "Out of memory in group computation\n");
3901 ctxt->nbErrors++;
3902 return;
3903 }
3904 i = 0;
3905 cur = def->attrs;
3906 while (cur != NULL) {
3907 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3908 i++;
3909 cur = cur->next;
3910 }
3911 cur = def->content;
3912 while (cur != NULL) {
3913 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3914 i++;
3915 cur = cur->next;
3916 }
3917
3918 for (i = 0;i < nbchild;i++) {
3919 if (list[i] == NULL)
3920 continue;
3921 for (j = 0;j < i;j++) {
3922 if (list[j] == NULL)
3923 continue;
3924 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3925 if (ret == 0) {
3926 if (ctxt->error != NULL)
3927 ctxt->error(ctxt->userData,
3928 "Attributes conflicts in group\n");
3929 ctxt->nbErrors++;
3930 }
3931 }
3932 }
3933 for (i = 0;i < nbchild;i++) {
3934 if (list[i] != NULL)
3935 xmlFree(list[i]);
3936 }
3937
3938 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003939 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003940}
3941
3942/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003943 * xmlRelaxNGComputeInterleaves:
3944 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003945 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003946 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003947 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003948 * A lot of work for preprocessing interleave definitions
3949 * is potentially needed to get a decent execution speed at runtime
3950 * - trying to get a total order on the element nodes generated
3951 * by the interleaves, order the list of interleave definitions
3952 * following that order.
3953 * - if <text/> is used to handle mixed content, it is better to
3954 * flag this in the define and simplify the runtime checking
3955 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003956 */
3957static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003958xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3959 xmlRelaxNGParserCtxtPtr ctxt,
3960 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003961 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003962
Daniel Veillardfd573f12003-03-16 17:52:32 +00003963 xmlRelaxNGPartitionPtr partitions = NULL;
3964 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3965 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003966 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003967 int nbgroups = 0;
3968 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003969 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003970 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003971
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003972 /*
3973 * Don't run that check in case of error. Infinite recursion
3974 * becomes possible.
3975 */
3976 if (ctxt->nbErrors != 0)
3977 return;
3978
Daniel Veillardfd573f12003-03-16 17:52:32 +00003979#ifdef DEBUG_INTERLEAVE
3980 xmlGenericError(xmlGenericErrorContext,
3981 "xmlRelaxNGComputeInterleaves(%s)\n",
3982 name);
3983#endif
3984 cur = def->content;
3985 while (cur != NULL) {
3986 nbchild++;
3987 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003988 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003989
3990#ifdef DEBUG_INTERLEAVE
3991 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3992#endif
3993 groups = (xmlRelaxNGInterleaveGroupPtr *)
3994 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3995 if (groups == NULL)
3996 goto error;
3997 cur = def->content;
3998 while (cur != NULL) {
3999 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4000 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4001 if (groups[nbgroups] == NULL)
4002 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004003 if (cur->type == XML_RELAXNG_TEXT)
4004 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004005 groups[nbgroups]->rule = cur;
4006 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4007 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4008 nbgroups++;
4009 cur = cur->next;
4010 }
4011#ifdef DEBUG_INTERLEAVE
4012 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4013#endif
4014
4015 /*
4016 * Let's check that all rules makes a partitions according to 7.4
4017 */
4018 partitions = (xmlRelaxNGPartitionPtr)
4019 xmlMalloc(sizeof(xmlRelaxNGPartition));
4020 if (partitions == NULL)
4021 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004022 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004023 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004024 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004025 for (i = 0;i < nbgroups;i++) {
4026 group = groups[i];
4027 for (j = i+1;j < nbgroups;j++) {
4028 if (groups[j] == NULL)
4029 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004030
Daniel Veillardfd573f12003-03-16 17:52:32 +00004031 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4032 groups[j]->defs);
4033 if (ret == 0) {
4034 if (ctxt->error != NULL)
4035 ctxt->error(ctxt->userData,
4036 "Element or text conflicts in interleave\n");
4037 ctxt->nbErrors++;
4038 }
4039 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4040 groups[j]->attrs);
4041 if (ret == 0) {
4042 if (ctxt->error != NULL)
4043 ctxt->error(ctxt->userData,
4044 "Attributes conflicts in interleave\n");
4045 ctxt->nbErrors++;
4046 }
4047 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004048 tmp = group->defs;
4049 if ((tmp != NULL) && (*tmp != NULL)) {
4050 while (*tmp != NULL) {
4051 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4052 res = xmlHashAddEntry2(partitions->triage,
4053 BAD_CAST "#text", NULL,
4054 (void *)(i + 1));
4055 if (res != 0)
4056 is_determinist = -1;
4057 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4058 ((*tmp)->name != NULL)) {
4059 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4060 res = xmlHashAddEntry2(partitions->triage,
4061 (*tmp)->name, NULL,
4062 (void *)(i + 1));
4063 else
4064 res = xmlHashAddEntry2(partitions->triage,
4065 (*tmp)->name, (*tmp)->ns,
4066 (void *)(i + 1));
4067 if (res != 0)
4068 is_determinist = -1;
4069 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4070 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4071 res = xmlHashAddEntry2(partitions->triage,
4072 BAD_CAST "#any", NULL,
4073 (void *)(i + 1));
4074 else
4075 res = xmlHashAddEntry2(partitions->triage,
4076 BAD_CAST "#any", (*tmp)->ns,
4077 (void *)(i + 1));
4078 if ((*tmp)->nameClass != NULL)
4079 is_determinist = 2;
4080 if (res != 0)
4081 is_determinist = -1;
4082 } else {
4083 is_determinist = -1;
4084 }
4085 tmp++;
4086 }
4087 } else {
4088 is_determinist = 0;
4089 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004090 }
4091 partitions->groups = groups;
4092
4093 /*
4094 * and save the partition list back in the def
4095 */
4096 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004097 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00004098 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004099 if (is_determinist == 1)
4100 partitions->flags = IS_DETERMINIST;
4101 if (is_determinist == 2)
4102 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004103 return;
4104
4105error:
4106 if (ctxt->error != NULL)
4107 ctxt->error(ctxt->userData,
4108 "Out of memory in interleave computation\n");
4109 ctxt->nbErrors++;
4110 if (groups != NULL) {
4111 for (i = 0;i < nbgroups;i++)
4112 if (groups[i] != NULL) {
4113 if (groups[i]->defs != NULL)
4114 xmlFree(groups[i]->defs);
4115 xmlFree(groups[i]);
4116 }
4117 xmlFree(groups);
4118 }
4119 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004120}
4121
4122/**
4123 * xmlRelaxNGParseInterleave:
4124 * @ctxt: a Relax-NG parser context
4125 * @node: the data node.
4126 *
4127 * parse the content of a RelaxNG interleave node.
4128 *
4129 * Returns the definition pointer or NULL in case of error
4130 */
4131static xmlRelaxNGDefinePtr
4132xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4133 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004134 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004135 xmlNodePtr child;
4136
Daniel Veillardfd573f12003-03-16 17:52:32 +00004137 def = xmlRelaxNGNewDefine(ctxt, node);
4138 if (def == NULL) {
4139 return(NULL);
4140 }
4141 def->type = XML_RELAXNG_INTERLEAVE;
4142
4143 if (ctxt->interleaves == NULL)
4144 ctxt->interleaves = xmlHashCreate(10);
4145 if (ctxt->interleaves == NULL) {
4146 if (ctxt->error != NULL)
4147 ctxt->error(ctxt->userData,
4148 "Failed to create interleaves hash table\n");
4149 ctxt->nbErrors++;
4150 } else {
4151 char name[32];
4152
4153 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4154 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4155 if (ctxt->error != NULL)
4156 ctxt->error(ctxt->userData,
4157 "Failed to add %s to hash table\n", name);
4158 ctxt->nbErrors++;
4159 }
4160 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004161 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004162 if (child == NULL) {
4163 if (ctxt->error != NULL)
4164 ctxt->error(ctxt->userData, "Element interleave is empty\n");
4165 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004166 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004167 while (child != NULL) {
4168 if (IS_RELAXNG(child, "element")) {
4169 cur = xmlRelaxNGParseElement(ctxt, child);
4170 } else {
4171 cur = xmlRelaxNGParsePattern(ctxt, child);
4172 }
4173 if (cur != NULL) {
4174 cur->parent = def;
4175 if (last == NULL) {
4176 def->content = last = cur;
4177 } else {
4178 last->next = cur;
4179 last = cur;
4180 }
4181 }
4182 child = child->next;
4183 }
4184
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004185 return(def);
4186}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004187
4188/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004189 * xmlRelaxNGParseInclude:
4190 * @ctxt: a Relax-NG parser context
4191 * @node: the include node
4192 *
4193 * Integrate the content of an include node in the current grammar
4194 *
4195 * Returns 0 in case of success or -1 in case of error
4196 */
4197static int
4198xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4199 xmlRelaxNGIncludePtr incl;
4200 xmlNodePtr root;
4201 int ret = 0, tmp;
4202
4203 incl = node->_private;
4204 if (incl == NULL) {
4205 if (ctxt->error != NULL)
4206 ctxt->error(ctxt->userData,
4207 "Include node has no data\n");
4208 ctxt->nbErrors++;
4209 return(-1);
4210 }
4211 root = xmlDocGetRootElement(incl->doc);
4212 if (root == NULL) {
4213 if (ctxt->error != NULL)
4214 ctxt->error(ctxt->userData,
4215 "Include document is empty\n");
4216 ctxt->nbErrors++;
4217 return(-1);
4218 }
4219 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4220 if (ctxt->error != NULL)
4221 ctxt->error(ctxt->userData,
4222 "Include document root is not a grammar\n");
4223 ctxt->nbErrors++;
4224 return(-1);
4225 }
4226
4227 /*
4228 * Merge the definition from both the include and the internal list
4229 */
4230 if (root->children != NULL) {
4231 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4232 if (tmp != 0)
4233 ret = -1;
4234 }
4235 if (node->children != NULL) {
4236 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4237 if (tmp != 0)
4238 ret = -1;
4239 }
4240 return(ret);
4241}
4242
4243/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004244 * xmlRelaxNGParseDefine:
4245 * @ctxt: a Relax-NG parser context
4246 * @node: the define node
4247 *
4248 * parse the content of a RelaxNG define element node.
4249 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004250 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004251 */
4252static int
4253xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4254 xmlChar *name;
4255 int ret = 0, tmp;
4256 xmlRelaxNGDefinePtr def;
4257 const xmlChar *olddefine;
4258
4259 name = xmlGetProp(node, BAD_CAST "name");
4260 if (name == NULL) {
4261 if (ctxt->error != NULL)
4262 ctxt->error(ctxt->userData,
4263 "define has no name\n");
4264 ctxt->nbErrors++;
4265 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004266 xmlRelaxNGNormExtSpace(name);
4267 if (xmlValidateNCName(name, 0)) {
4268 if (ctxt->error != NULL)
4269 ctxt->error(ctxt->userData,
4270 "define name '%s' is not an NCName\n",
4271 name);
4272 ctxt->nbErrors++;
4273 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004274 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004275 if (def == NULL) {
4276 xmlFree(name);
4277 return(-1);
4278 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004279 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004280 def->name = name;
4281 if (node->children == NULL) {
4282 if (ctxt->error != NULL)
4283 ctxt->error(ctxt->userData,
4284 "define has no children\n");
4285 ctxt->nbErrors++;
4286 } else {
4287 olddefine = ctxt->define;
4288 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00004289 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004290 ctxt->define = olddefine;
4291 }
4292 if (ctxt->grammar->defs == NULL)
4293 ctxt->grammar->defs = xmlHashCreate(10);
4294 if (ctxt->grammar->defs == NULL) {
4295 if (ctxt->error != NULL)
4296 ctxt->error(ctxt->userData,
4297 "Could not create definition hash\n");
4298 ctxt->nbErrors++;
4299 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004300 } else {
4301 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4302 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00004303 xmlRelaxNGDefinePtr prev;
4304
4305 prev = xmlHashLookup(ctxt->grammar->defs, name);
4306 if (prev == NULL) {
4307 if (ctxt->error != NULL)
4308 ctxt->error(ctxt->userData,
4309 "Internal error on define aggregation of %s\n",
4310 name);
4311 ctxt->nbErrors++;
4312 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00004313 } else {
4314 while (prev->nextHash != NULL)
4315 prev = prev->nextHash;
4316 prev->nextHash = def;
4317 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004318 }
4319 }
4320 }
4321 return(ret);
4322}
4323
4324/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004325 * xmlRelaxNGProcessExternalRef:
4326 * @ctxt: the parser context
4327 * @node: the externlRef node
4328 *
4329 * Process and compile an externlRef node
4330 *
4331 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4332 */
4333static xmlRelaxNGDefinePtr
4334xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4335 xmlRelaxNGDocumentPtr docu;
4336 xmlNodePtr root, tmp;
4337 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004338 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004339 xmlRelaxNGDefinePtr def;
4340
4341 docu = node->_private;
4342 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004343 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004344 if (def == NULL)
4345 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004346 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004347
4348 if (docu->content == NULL) {
4349 /*
4350 * Then do the parsing for good
4351 */
4352 root = xmlDocGetRootElement(docu->doc);
4353 if (root == NULL) {
4354 if (ctxt->error != NULL)
4355 ctxt->error(ctxt->userData,
4356 "xmlRelaxNGParse: %s is empty\n",
4357 ctxt->URL);
4358 ctxt->nbErrors++;
4359 return (NULL);
4360 }
4361 /*
4362 * ns transmission rules
4363 */
4364 ns = xmlGetProp(root, BAD_CAST "ns");
4365 if (ns == NULL) {
4366 tmp = node;
4367 while ((tmp != NULL) &&
4368 (tmp->type == XML_ELEMENT_NODE)) {
4369 ns = xmlGetProp(tmp, BAD_CAST "ns");
4370 if (ns != NULL) {
4371 break;
4372 }
4373 tmp = tmp->parent;
4374 }
4375 if (ns != NULL) {
4376 xmlSetProp(root, BAD_CAST "ns", ns);
4377 newNs = 1;
4378 xmlFree(ns);
4379 }
4380 } else {
4381 xmlFree(ns);
4382 }
4383
4384 /*
4385 * Parsing to get a precompiled schemas.
4386 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004387 oldflags = ctxt->flags;
4388 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004389 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004390 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004391 if ((docu->schema != NULL) &&
4392 (docu->schema->topgrammar != NULL)) {
4393 docu->content = docu->schema->topgrammar->start;
4394 }
4395
4396 /*
4397 * the externalRef may be reused in a different ns context
4398 */
4399 if (newNs == 1) {
4400 xmlUnsetProp(root, BAD_CAST "ns");
4401 }
4402 }
4403 def->content = docu->content;
4404 } else {
4405 def = NULL;
4406 }
4407 return(def);
4408}
4409
4410/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004411 * xmlRelaxNGParsePattern:
4412 * @ctxt: a Relax-NG parser context
4413 * @node: the pattern node.
4414 *
4415 * parse the content of a RelaxNG pattern node.
4416 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004417 * Returns the definition pointer or NULL in case of error or if no
4418 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004419 */
4420static xmlRelaxNGDefinePtr
4421xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4422 xmlRelaxNGDefinePtr def = NULL;
4423
Daniel Veillardd2298792003-02-14 16:54:11 +00004424 if (node == NULL) {
4425 return(NULL);
4426 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004427 if (IS_RELAXNG(node, "element")) {
4428 def = xmlRelaxNGParseElement(ctxt, node);
4429 } else if (IS_RELAXNG(node, "attribute")) {
4430 def = xmlRelaxNGParseAttribute(ctxt, node);
4431 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004432 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004433 if (def == NULL)
4434 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004435 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004436 if (node->children != NULL) {
4437 if (ctxt->error != NULL)
4438 ctxt->error(ctxt->userData, "empty: had a child node\n");
4439 ctxt->nbErrors++;
4440 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004441 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004442 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004443 if (def == NULL)
4444 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004445 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004446 if (node->children != NULL) {
4447 if (ctxt->error != NULL)
4448 ctxt->error(ctxt->userData, "text: had a child node\n");
4449 ctxt->nbErrors++;
4450 }
4451 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004452 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004453 if (def == NULL)
4454 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004455 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004456 if (node->children == NULL) {
4457 if (ctxt->error != NULL)
4458 ctxt->error(ctxt->userData,
4459 "Element %s is empty\n", node->name);
4460 ctxt->nbErrors++;
4461 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004462 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004463 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004464 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004465 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004466 if (def == NULL)
4467 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004468 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004469 if (node->children == NULL) {
4470 if (ctxt->error != NULL)
4471 ctxt->error(ctxt->userData,
4472 "Element %s is empty\n", node->name);
4473 ctxt->nbErrors++;
4474 } else {
4475 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4476 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004477 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004478 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004479 if (def == NULL)
4480 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004481 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004482 if (node->children == NULL) {
4483 if (ctxt->error != NULL)
4484 ctxt->error(ctxt->userData,
4485 "Element %s is empty\n", node->name);
4486 ctxt->nbErrors++;
4487 } else {
4488 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4489 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004490 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004491 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004492 if (def == NULL)
4493 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004494 def->type = XML_RELAXNG_CHOICE;
4495 if (node->children == NULL) {
4496 if (ctxt->error != NULL)
4497 ctxt->error(ctxt->userData,
4498 "Element %s is empty\n", node->name);
4499 ctxt->nbErrors++;
4500 } else {
4501 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4502 }
4503 } else if (IS_RELAXNG(node, "group")) {
4504 def = xmlRelaxNGNewDefine(ctxt, node);
4505 if (def == NULL)
4506 return(NULL);
4507 def->type = XML_RELAXNG_GROUP;
4508 if (node->children == NULL) {
4509 if (ctxt->error != NULL)
4510 ctxt->error(ctxt->userData,
4511 "Element %s is empty\n", node->name);
4512 ctxt->nbErrors++;
4513 } else {
4514 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4515 }
4516 } else if (IS_RELAXNG(node, "ref")) {
4517 def = xmlRelaxNGNewDefine(ctxt, node);
4518 if (def == NULL)
4519 return(NULL);
4520 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004521 def->name = xmlGetProp(node, BAD_CAST "name");
4522 if (def->name == NULL) {
4523 if (ctxt->error != NULL)
4524 ctxt->error(ctxt->userData,
4525 "ref has no name\n");
4526 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004527 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004528 xmlRelaxNGNormExtSpace(def->name);
4529 if (xmlValidateNCName(def->name, 0)) {
4530 if (ctxt->error != NULL)
4531 ctxt->error(ctxt->userData,
4532 "ref name '%s' is not an NCName\n",
4533 def->name);
4534 ctxt->nbErrors++;
4535 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004536 }
4537 if (node->children != NULL) {
4538 if (ctxt->error != NULL)
4539 ctxt->error(ctxt->userData,
4540 "ref is not empty\n");
4541 ctxt->nbErrors++;
4542 }
4543 if (ctxt->grammar->refs == NULL)
4544 ctxt->grammar->refs = xmlHashCreate(10);
4545 if (ctxt->grammar->refs == NULL) {
4546 if (ctxt->error != NULL)
4547 ctxt->error(ctxt->userData,
4548 "Could not create references hash\n");
4549 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004550 def = NULL;
4551 } else {
4552 int tmp;
4553
4554 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4555 if (tmp < 0) {
4556 xmlRelaxNGDefinePtr prev;
4557
4558 prev = (xmlRelaxNGDefinePtr)
4559 xmlHashLookup(ctxt->grammar->refs, def->name);
4560 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004561 if (def->name != NULL) {
4562 if (ctxt->error != NULL)
4563 ctxt->error(ctxt->userData,
4564 "Error refs definitions '%s'\n",
4565 def->name);
4566 } else {
4567 if (ctxt->error != NULL)
4568 ctxt->error(ctxt->userData,
4569 "Error refs definitions\n");
4570 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004571 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004572 def = NULL;
4573 } else {
4574 def->nextHash = prev->nextHash;
4575 prev->nextHash = def;
4576 }
4577 }
4578 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004579 } else if (IS_RELAXNG(node, "data")) {
4580 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004581 } else if (IS_RELAXNG(node, "value")) {
4582 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004583 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004584 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004585 if (def == NULL)
4586 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004587 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004588 if (node->children == NULL) {
4589 if (ctxt->error != NULL)
4590 ctxt->error(ctxt->userData,
4591 "Element %s is empty\n", node->name);
4592 ctxt->nbErrors++;
4593 } else {
4594 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4595 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004596 } else if (IS_RELAXNG(node, "interleave")) {
4597 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004598 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004599 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004600 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004601 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004602 if (def == NULL)
4603 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004604 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004605 if (node->children != NULL) {
4606 if (ctxt->error != NULL)
4607 ctxt->error(ctxt->userData,
4608 "xmlRelaxNGParse: notAllowed element is not empty\n");
4609 ctxt->nbErrors++;
4610 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004611 } else if (IS_RELAXNG(node, "grammar")) {
4612 xmlRelaxNGGrammarPtr grammar, old;
4613 xmlRelaxNGGrammarPtr oldparent;
4614
Daniel Veillardc482e262003-02-26 14:48:48 +00004615#ifdef DEBUG_GRAMMAR
4616 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4617#endif
4618
Daniel Veillard419a7682003-02-03 23:22:49 +00004619 oldparent = ctxt->parentgrammar;
4620 old = ctxt->grammar;
4621 ctxt->parentgrammar = old;
4622 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4623 if (old != NULL) {
4624 ctxt->grammar = old;
4625 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004626#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004627 if (grammar != NULL) {
4628 grammar->next = old->next;
4629 old->next = grammar;
4630 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004631#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004632 }
4633 if (grammar != NULL)
4634 def = grammar->start;
4635 else
4636 def = NULL;
4637 } else if (IS_RELAXNG(node, "parentRef")) {
4638 if (ctxt->parentgrammar == NULL) {
4639 if (ctxt->error != NULL)
4640 ctxt->error(ctxt->userData,
4641 "Use of parentRef without a parent grammar\n");
4642 ctxt->nbErrors++;
4643 return(NULL);
4644 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004645 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004646 if (def == NULL)
4647 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004648 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004649 def->name = xmlGetProp(node, BAD_CAST "name");
4650 if (def->name == NULL) {
4651 if (ctxt->error != NULL)
4652 ctxt->error(ctxt->userData,
4653 "parentRef has no name\n");
4654 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004655 } else {
4656 xmlRelaxNGNormExtSpace(def->name);
4657 if (xmlValidateNCName(def->name, 0)) {
4658 if (ctxt->error != NULL)
4659 ctxt->error(ctxt->userData,
4660 "parentRef name '%s' is not an NCName\n",
4661 def->name);
4662 ctxt->nbErrors++;
4663 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004664 }
4665 if (node->children != NULL) {
4666 if (ctxt->error != NULL)
4667 ctxt->error(ctxt->userData,
4668 "parentRef is not empty\n");
4669 ctxt->nbErrors++;
4670 }
4671 if (ctxt->parentgrammar->refs == NULL)
4672 ctxt->parentgrammar->refs = xmlHashCreate(10);
4673 if (ctxt->parentgrammar->refs == NULL) {
4674 if (ctxt->error != NULL)
4675 ctxt->error(ctxt->userData,
4676 "Could not create references hash\n");
4677 ctxt->nbErrors++;
4678 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004679 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004680 int tmp;
4681
4682 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4683 if (tmp < 0) {
4684 xmlRelaxNGDefinePtr prev;
4685
4686 prev = (xmlRelaxNGDefinePtr)
4687 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4688 if (prev == NULL) {
4689 if (ctxt->error != NULL)
4690 ctxt->error(ctxt->userData,
4691 "Internal error parentRef definitions '%s'\n",
4692 def->name);
4693 ctxt->nbErrors++;
4694 def = NULL;
4695 } else {
4696 def->nextHash = prev->nextHash;
4697 prev->nextHash = def;
4698 }
4699 }
4700 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004701 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004702 if (node->children == NULL) {
4703 if (ctxt->error != NULL)
4704 ctxt->error(ctxt->userData,
4705 "Mixed is empty\n");
4706 ctxt->nbErrors++;
4707 def = NULL;
4708 } else {
4709 def = xmlRelaxNGParseInterleave(ctxt, node);
4710 if (def != NULL) {
4711 xmlRelaxNGDefinePtr tmp;
4712
4713 if ((def->content != NULL) && (def->content->next != NULL)) {
4714 tmp = xmlRelaxNGNewDefine(ctxt, node);
4715 if (tmp != NULL) {
4716 tmp->type = XML_RELAXNG_GROUP;
4717 tmp->content = def->content;
4718 def->content = tmp;
4719 }
4720 }
4721
4722 tmp = xmlRelaxNGNewDefine(ctxt, node);
4723 if (tmp == NULL)
4724 return(def);
4725 tmp->type = XML_RELAXNG_TEXT;
4726 tmp->next = def->content;
4727 def->content = tmp;
4728 }
4729 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004730 } else {
4731 if (ctxt->error != NULL)
4732 ctxt->error(ctxt->userData,
4733 "Unexpected node %s is not a pattern\n",
4734 node->name);
4735 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004736 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004737 }
4738 return(def);
4739}
4740
4741/**
4742 * xmlRelaxNGParseAttribute:
4743 * @ctxt: a Relax-NG parser context
4744 * @node: the element node
4745 *
4746 * parse the content of a RelaxNG attribute node.
4747 *
4748 * Returns the definition pointer or NULL in case of error.
4749 */
4750static xmlRelaxNGDefinePtr
4751xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004752 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004753 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004754 int old_flags;
4755
Daniel Veillardfd573f12003-03-16 17:52:32 +00004756 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004757 if (ret == NULL)
4758 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004759 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004760 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004761 child = node->children;
4762 if (child == NULL) {
4763 if (ctxt->error != NULL)
4764 ctxt->error(ctxt->userData,
4765 "xmlRelaxNGParseattribute: attribute has no children\n");
4766 ctxt->nbErrors++;
4767 return(ret);
4768 }
4769 old_flags = ctxt->flags;
4770 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004771 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4772 if (cur != NULL)
4773 child = child->next;
4774
Daniel Veillardd2298792003-02-14 16:54:11 +00004775 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004776 cur = xmlRelaxNGParsePattern(ctxt, child);
4777 if (cur != NULL) {
4778 switch (cur->type) {
4779 case XML_RELAXNG_EMPTY:
4780 case XML_RELAXNG_NOT_ALLOWED:
4781 case XML_RELAXNG_TEXT:
4782 case XML_RELAXNG_ELEMENT:
4783 case XML_RELAXNG_DATATYPE:
4784 case XML_RELAXNG_VALUE:
4785 case XML_RELAXNG_LIST:
4786 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004787 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004788 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004789 case XML_RELAXNG_DEF:
4790 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004791 case XML_RELAXNG_ZEROORMORE:
4792 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004793 case XML_RELAXNG_CHOICE:
4794 case XML_RELAXNG_GROUP:
4795 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004796 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004797 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004798 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004799 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004800 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004801 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004802 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004803 if (ctxt->error != NULL)
4804 ctxt->error(ctxt->userData,
4805 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004806 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004807 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004808 case XML_RELAXNG_NOOP:
4809 TODO
4810 if (ctxt->error != NULL)
4811 ctxt->error(ctxt->userData,
4812 "Internal error, noop found\n");
4813 ctxt->nbErrors++;
4814 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004815 }
4816 }
4817 child = child->next;
4818 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004819 if (child != NULL) {
4820 if (ctxt->error != NULL)
4821 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4822 ctxt->nbErrors++;
4823 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004824 ctxt->flags = old_flags;
4825 return(ret);
4826}
4827
4828/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004829 * xmlRelaxNGParseExceptNameClass:
4830 * @ctxt: a Relax-NG parser context
4831 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004832 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004833 *
4834 * parse the content of a RelaxNG nameClass node.
4835 *
4836 * Returns the definition pointer or NULL in case of error.
4837 */
4838static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004839xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4840 xmlNodePtr node, int attr) {
4841 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4842 xmlNodePtr child;
4843
Daniel Veillardd2298792003-02-14 16:54:11 +00004844 if (!IS_RELAXNG(node, "except")) {
4845 if (ctxt->error != NULL)
4846 ctxt->error(ctxt->userData,
4847 "Expecting an except node\n");
4848 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004849 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004850 }
4851 if (node->next != NULL) {
4852 if (ctxt->error != NULL)
4853 ctxt->error(ctxt->userData,
4854 "exceptNameClass allows only a single except node\n");
4855 ctxt->nbErrors++;
4856 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004857 if (node->children == NULL) {
4858 if (ctxt->error != NULL)
4859 ctxt->error(ctxt->userData,
4860 "except has no content\n");
4861 ctxt->nbErrors++;
4862 return(NULL);
4863 }
4864
Daniel Veillardfd573f12003-03-16 17:52:32 +00004865 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004866 if (ret == NULL)
4867 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004868 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004869 child = node->children;
4870 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004871 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004872 if (cur == NULL)
4873 break;
4874 if (attr)
4875 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004876 else
4877 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004878
Daniel Veillard419a7682003-02-03 23:22:49 +00004879 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004880 if (last == NULL) {
4881 ret->content = cur;
4882 } else {
4883 last->next = cur;
4884 }
4885 last = cur;
4886 }
4887 child = child->next;
4888 }
4889
4890 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004891}
4892
4893/**
4894 * xmlRelaxNGParseNameClass:
4895 * @ctxt: a Relax-NG parser context
4896 * @node: the nameClass node
4897 * @def: the current definition
4898 *
4899 * parse the content of a RelaxNG nameClass node.
4900 *
4901 * Returns the definition pointer or NULL in case of error.
4902 */
4903static xmlRelaxNGDefinePtr
4904xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4905 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004906 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004907 xmlChar *val;
4908
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004909 ret = def;
4910 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4911 (IS_RELAXNG(node, "nsName"))) {
4912 if ((def->type != XML_RELAXNG_ELEMENT) &&
4913 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004914 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004915 if (ret == NULL)
4916 return(NULL);
4917 ret->parent = def;
4918 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4919 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004920 else
4921 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004922 }
4923 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004924 if (IS_RELAXNG(node, "name")) {
4925 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004926 xmlRelaxNGNormExtSpace(val);
4927 if (xmlValidateNCName(val, 0)) {
4928 if (ctxt->error != NULL) {
4929 if (node->parent != NULL)
4930 ctxt->error(ctxt->userData,
4931 "Element %s name '%s' is not an NCName\n",
4932 node->parent->name, val);
4933 else
4934 ctxt->error(ctxt->userData,
4935 "name '%s' is not an NCName\n",
4936 val);
4937 }
4938 ctxt->nbErrors++;
4939 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004940 ret->name = val;
4941 val = xmlGetProp(node, BAD_CAST "ns");
4942 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004943 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4944 (val != NULL) &&
4945 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4946 ctxt->error(ctxt->userData,
4947 "Attribute with namespace '%s' is not allowed\n",
4948 val);
4949 ctxt->nbErrors++;
4950 }
4951 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4952 (val != NULL) &&
4953 (val[0] == 0) &&
4954 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4955 ctxt->error(ctxt->userData,
4956 "Attribute with QName 'xmlns' is not allowed\n",
4957 val);
4958 ctxt->nbErrors++;
4959 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004960 } else if (IS_RELAXNG(node, "anyName")) {
4961 ret->name = NULL;
4962 ret->ns = NULL;
4963 if (node->children != NULL) {
4964 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004965 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4966 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004967 }
4968 } else if (IS_RELAXNG(node, "nsName")) {
4969 ret->name = NULL;
4970 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4971 if (ret->ns == NULL) {
4972 if (ctxt->error != NULL)
4973 ctxt->error(ctxt->userData,
4974 "nsName has no ns attribute\n");
4975 ctxt->nbErrors++;
4976 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004977 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4978 (ret->ns != NULL) &&
4979 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4980 ctxt->error(ctxt->userData,
4981 "Attribute with namespace '%s' is not allowed\n",
4982 ret->ns);
4983 ctxt->nbErrors++;
4984 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004985 if (node->children != NULL) {
4986 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004987 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4988 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004989 }
4990 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004991 xmlNodePtr child;
4992 xmlRelaxNGDefinePtr last = NULL;
4993
4994 ret = xmlRelaxNGNewDefine(ctxt, node);
4995 if (ret == NULL)
4996 return(NULL);
4997 ret->parent = def;
4998 ret->type = XML_RELAXNG_CHOICE;
4999
Daniel Veillardd2298792003-02-14 16:54:11 +00005000 if (node->children == NULL) {
5001 if (ctxt->error != NULL)
5002 ctxt->error(ctxt->userData,
5003 "Element choice is empty\n");
5004 ctxt->nbErrors++;
5005 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005006
5007 child = node->children;
5008 while (child != NULL) {
5009 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5010 if (tmp != NULL) {
5011 if (last == NULL) {
5012 last = ret->nameClass = tmp;
5013 } else {
5014 last->next = tmp;
5015 last = tmp;
5016 }
5017 }
5018 child = child->next;
5019 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005020 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005021 } else {
5022 if (ctxt->error != NULL)
5023 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00005024 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005025 node->name);
5026 ctxt->nbErrors++;
5027 return(NULL);
5028 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005029 if (ret != def) {
5030 if (def->nameClass == NULL) {
5031 def->nameClass = ret;
5032 } else {
5033 tmp = def->nameClass;
5034 while (tmp->next != NULL) {
5035 tmp = tmp->next;
5036 }
5037 tmp->next = ret;
5038 }
5039 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005040 return(ret);
5041}
5042
5043/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005044 * xmlRelaxNGParseElement:
5045 * @ctxt: a Relax-NG parser context
5046 * @node: the element node
5047 *
5048 * parse the content of a RelaxNG element node.
5049 *
5050 * Returns the definition pointer or NULL in case of error.
5051 */
5052static xmlRelaxNGDefinePtr
5053xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5054 xmlRelaxNGDefinePtr ret, cur, last;
5055 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005056 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005057
Daniel Veillardfd573f12003-03-16 17:52:32 +00005058 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005059 if (ret == NULL)
5060 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005061 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005062 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005063 child = node->children;
5064 if (child == NULL) {
5065 if (ctxt->error != NULL)
5066 ctxt->error(ctxt->userData,
5067 "xmlRelaxNGParseElement: element has no children\n");
5068 ctxt->nbErrors++;
5069 return(ret);
5070 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005071 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5072 if (cur != NULL)
5073 child = child->next;
5074
Daniel Veillard6eadf632003-01-23 18:29:16 +00005075 if (child == NULL) {
5076 if (ctxt->error != NULL)
5077 ctxt->error(ctxt->userData,
5078 "xmlRelaxNGParseElement: element has no content\n");
5079 ctxt->nbErrors++;
5080 return(ret);
5081 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005082 olddefine = ctxt->define;
5083 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005084 last = NULL;
5085 while (child != NULL) {
5086 cur = xmlRelaxNGParsePattern(ctxt, child);
5087 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005088 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005089 switch (cur->type) {
5090 case XML_RELAXNG_EMPTY:
5091 case XML_RELAXNG_NOT_ALLOWED:
5092 case XML_RELAXNG_TEXT:
5093 case XML_RELAXNG_ELEMENT:
5094 case XML_RELAXNG_DATATYPE:
5095 case XML_RELAXNG_VALUE:
5096 case XML_RELAXNG_LIST:
5097 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00005098 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005099 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005100 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005101 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005102 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005103 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005104 case XML_RELAXNG_CHOICE:
5105 case XML_RELAXNG_GROUP:
5106 case XML_RELAXNG_INTERLEAVE:
5107 if (last == NULL) {
5108 ret->content = last = cur;
5109 } else {
5110 if ((last->type == XML_RELAXNG_ELEMENT) &&
5111 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005112 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005113 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005114 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005115 ret->content->content = last;
5116 } else {
5117 ret->content = last;
5118 }
5119 }
5120 last->next = cur;
5121 last = cur;
5122 }
5123 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005124 case XML_RELAXNG_ATTRIBUTE:
5125 cur->next = ret->attrs;
5126 ret->attrs = cur;
5127 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005128 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00005129 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00005130 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005131 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005132 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005133 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00005134 case XML_RELAXNG_NOOP:
5135 TODO
5136 if (ctxt->error != NULL)
5137 ctxt->error(ctxt->userData,
5138 "Internal error, noop found\n");
5139 ctxt->nbErrors++;
5140 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005141 }
5142 }
5143 child = child->next;
5144 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005145 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005146 return(ret);
5147}
5148
5149/**
5150 * xmlRelaxNGParsePatterns:
5151 * @ctxt: a Relax-NG parser context
5152 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005153 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005154 *
5155 * parse the content of a RelaxNG start node.
5156 *
5157 * Returns the definition pointer or NULL in case of error.
5158 */
5159static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005160xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5161 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005162 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005163
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005164 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005165 while (nodes != NULL) {
5166 if (IS_RELAXNG(nodes, "element")) {
5167 cur = xmlRelaxNGParseElement(ctxt, nodes);
5168 if (def == NULL) {
5169 def = last = cur;
5170 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00005171 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5172 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005173 def = xmlRelaxNGNewDefine(ctxt, nodes);
5174 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005175 def->content = last;
5176 }
5177 last->next = cur;
5178 last = cur;
5179 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005180 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005181 } else {
5182 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00005183 if (cur != NULL) {
5184 if (def == NULL) {
5185 def = last = cur;
5186 } else {
5187 last->next = cur;
5188 last = cur;
5189 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005190 }
5191 }
5192 nodes = nodes->next;
5193 }
5194 return(def);
5195}
5196
5197/**
5198 * xmlRelaxNGParseStart:
5199 * @ctxt: a Relax-NG parser context
5200 * @nodes: start children nodes
5201 *
5202 * parse the content of a RelaxNG start node.
5203 *
5204 * Returns 0 in case of success, -1 in case of error
5205 */
5206static int
5207xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5208 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005209 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005210
Daniel Veillardd2298792003-02-14 16:54:11 +00005211 if (nodes == NULL) {
5212 if (ctxt->error != NULL)
5213 ctxt->error(ctxt->userData,
5214 "start has no children\n");
5215 ctxt->nbErrors++;
5216 return(-1);
5217 }
5218 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005219 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005220 if (def == NULL)
5221 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005222 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00005223 if (nodes->children != NULL) {
5224 if (ctxt->error != NULL)
5225 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005226 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005227 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005228 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005229 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005230 if (def == NULL)
5231 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005232 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00005233 if (nodes->children != NULL) {
5234 if (ctxt->error != NULL)
5235 ctxt->error(ctxt->userData,
5236 "element notAllowed is not empty\n");
5237 ctxt->nbErrors++;
5238 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005239 } else {
5240 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005241 }
5242 if (ctxt->grammar->start != NULL) {
5243 last = ctxt->grammar->start;
5244 while (last->next != NULL)
5245 last = last->next;
5246 last->next = def;
5247 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005248 ctxt->grammar->start = def;
5249 }
5250 nodes = nodes->next;
5251 if (nodes != NULL) {
5252 if (ctxt->error != NULL)
5253 ctxt->error(ctxt->userData,
5254 "start more than one children\n");
5255 ctxt->nbErrors++;
5256 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005257 }
5258 return(ret);
5259}
5260
5261/**
5262 * xmlRelaxNGParseGrammarContent:
5263 * @ctxt: a Relax-NG parser context
5264 * @nodes: grammar children nodes
5265 *
5266 * parse the content of a RelaxNG grammar node.
5267 *
5268 * Returns 0 in case of success, -1 in case of error
5269 */
5270static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005271xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005272{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005273 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005274
5275 if (nodes == NULL) {
5276 if (ctxt->error != NULL)
5277 ctxt->error(ctxt->userData,
5278 "grammar has no children\n");
5279 ctxt->nbErrors++;
5280 return(-1);
5281 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005282 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005283 if (IS_RELAXNG(nodes, "start")) {
5284 if (nodes->children == NULL) {
5285 if (ctxt->error != NULL)
5286 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00005287 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005288 ctxt->nbErrors++;
5289 } else {
5290 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5291 if (tmp != 0)
5292 ret = -1;
5293 }
5294 } else if (IS_RELAXNG(nodes, "define")) {
5295 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5296 if (tmp != 0)
5297 ret = -1;
5298 } else if (IS_RELAXNG(nodes, "include")) {
5299 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5300 if (tmp != 0)
5301 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005302 } else {
5303 if (ctxt->error != NULL)
5304 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005305 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005306 ctxt->nbErrors++;
5307 ret = -1;
5308 }
5309 nodes = nodes->next;
5310 }
5311 return (ret);
5312}
5313
5314/**
5315 * xmlRelaxNGCheckReference:
5316 * @ref: the ref
5317 * @ctxt: a Relax-NG parser context
5318 * @name: the name associated to the defines
5319 *
5320 * Applies the 4.17. combine attribute rule for all the define
5321 * element of a given grammar using the same name.
5322 */
5323static void
5324xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5325 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5326 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005327 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005328
5329 grammar = ctxt->grammar;
5330 if (grammar == NULL) {
5331 if (ctxt->error != NULL)
5332 ctxt->error(ctxt->userData,
5333 "Internal error: no grammar in CheckReference %s\n",
5334 name);
5335 ctxt->nbErrors++;
5336 return;
5337 }
5338 if (ref->content != NULL) {
5339 if (ctxt->error != NULL)
5340 ctxt->error(ctxt->userData,
5341 "Internal error: reference has content in CheckReference %s\n",
5342 name);
5343 ctxt->nbErrors++;
5344 return;
5345 }
5346 if (grammar->defs != NULL) {
5347 def = xmlHashLookup(grammar->defs, name);
5348 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005349 cur = ref;
5350 while (cur != NULL) {
5351 cur->content = def;
5352 cur = cur->nextHash;
5353 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005354 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005355 if (ctxt->error != NULL)
5356 ctxt->error(ctxt->userData,
5357 "Reference %s has no matching definition\n",
5358 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005359 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005360 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005361 } else {
5362 if (ctxt->error != NULL)
5363 ctxt->error(ctxt->userData,
5364 "Reference %s has no matching definition\n",
5365 name);
5366 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005367 }
5368 /*
5369 * TODO: make a closure and verify there is no loop !
5370 */
5371}
5372
5373/**
5374 * xmlRelaxNGCheckCombine:
5375 * @define: the define(s) list
5376 * @ctxt: a Relax-NG parser context
5377 * @name: the name associated to the defines
5378 *
5379 * Applies the 4.17. combine attribute rule for all the define
5380 * element of a given grammar using the same name.
5381 */
5382static void
5383xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5384 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5385 xmlChar *combine;
5386 int choiceOrInterleave = -1;
5387 int missing = 0;
5388 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5389
5390 if (define->nextHash == NULL)
5391 return;
5392 cur = define;
5393 while (cur != NULL) {
5394 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5395 if (combine != NULL) {
5396 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5397 if (choiceOrInterleave == -1)
5398 choiceOrInterleave = 1;
5399 else if (choiceOrInterleave == 0) {
5400 if (ctxt->error != NULL)
5401 ctxt->error(ctxt->userData,
5402 "Defines for %s use both 'choice' and 'interleave'\n",
5403 name);
5404 ctxt->nbErrors++;
5405 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005406 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005407 if (choiceOrInterleave == -1)
5408 choiceOrInterleave = 0;
5409 else if (choiceOrInterleave == 1) {
5410 if (ctxt->error != NULL)
5411 ctxt->error(ctxt->userData,
5412 "Defines for %s use both 'choice' and 'interleave'\n",
5413 name);
5414 ctxt->nbErrors++;
5415 }
5416 } else {
5417 if (ctxt->error != NULL)
5418 ctxt->error(ctxt->userData,
5419 "Defines for %s use unknown combine value '%s''\n",
5420 name, combine);
5421 ctxt->nbErrors++;
5422 }
5423 xmlFree(combine);
5424 } else {
5425 if (missing == 0)
5426 missing = 1;
5427 else {
5428 if (ctxt->error != NULL)
5429 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005430 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005431 name);
5432 ctxt->nbErrors++;
5433 }
5434 }
5435
5436 cur = cur->nextHash;
5437 }
5438#ifdef DEBUG
5439 xmlGenericError(xmlGenericErrorContext,
5440 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5441 name, choiceOrInterleave);
5442#endif
5443 if (choiceOrInterleave == -1)
5444 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005445 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005446 if (cur == NULL)
5447 return;
5448 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005449 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005450 else
5451 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005452 tmp = define;
5453 last = NULL;
5454 while (tmp != NULL) {
5455 if (tmp->content != NULL) {
5456 if (tmp->content->next != NULL) {
5457 /*
5458 * we need first to create a wrapper.
5459 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005460 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005461 if (tmp2 == NULL)
5462 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005463 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005464 tmp2->content = tmp->content;
5465 } else {
5466 tmp2 = tmp->content;
5467 }
5468 if (last == NULL) {
5469 cur->content = tmp2;
5470 } else {
5471 last->next = tmp2;
5472 }
5473 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005474 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005475 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005476 tmp = tmp->nextHash;
5477 }
5478 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005479 if (choiceOrInterleave == 0) {
5480 if (ctxt->interleaves == NULL)
5481 ctxt->interleaves = xmlHashCreate(10);
5482 if (ctxt->interleaves == NULL) {
5483 if (ctxt->error != NULL)
5484 ctxt->error(ctxt->userData,
5485 "Failed to create interleaves hash table\n");
5486 ctxt->nbErrors++;
5487 } else {
5488 char tmpname[32];
5489
5490 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5491 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5492 if (ctxt->error != NULL)
5493 ctxt->error(ctxt->userData,
5494 "Failed to add %s to hash table\n", tmpname);
5495 ctxt->nbErrors++;
5496 }
5497 }
5498 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005499}
5500
5501/**
5502 * xmlRelaxNGCombineStart:
5503 * @ctxt: a Relax-NG parser context
5504 * @grammar: the grammar
5505 *
5506 * Applies the 4.17. combine rule for all the start
5507 * element of a given grammar.
5508 */
5509static void
5510xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5511 xmlRelaxNGGrammarPtr grammar) {
5512 xmlRelaxNGDefinePtr starts;
5513 xmlChar *combine;
5514 int choiceOrInterleave = -1;
5515 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005516 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005517
Daniel Veillard2df2de22003-02-17 23:34:33 +00005518 starts = grammar->start;
5519 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005520 return;
5521 cur = starts;
5522 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005523 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5524 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5525 combine = NULL;
5526 if (ctxt->error != NULL)
5527 ctxt->error(ctxt->userData,
5528 "Internal error: start element not found\n");
5529 ctxt->nbErrors++;
5530 } else {
5531 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5532 }
5533
Daniel Veillard6eadf632003-01-23 18:29:16 +00005534 if (combine != NULL) {
5535 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5536 if (choiceOrInterleave == -1)
5537 choiceOrInterleave = 1;
5538 else if (choiceOrInterleave == 0) {
5539 if (ctxt->error != NULL)
5540 ctxt->error(ctxt->userData,
5541 "<start> use both 'choice' and 'interleave'\n");
5542 ctxt->nbErrors++;
5543 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005544 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005545 if (choiceOrInterleave == -1)
5546 choiceOrInterleave = 0;
5547 else if (choiceOrInterleave == 1) {
5548 if (ctxt->error != NULL)
5549 ctxt->error(ctxt->userData,
5550 "<start> use both 'choice' and 'interleave'\n");
5551 ctxt->nbErrors++;
5552 }
5553 } else {
5554 if (ctxt->error != NULL)
5555 ctxt->error(ctxt->userData,
5556 "<start> uses unknown combine value '%s''\n", combine);
5557 ctxt->nbErrors++;
5558 }
5559 xmlFree(combine);
5560 } else {
5561 if (missing == 0)
5562 missing = 1;
5563 else {
5564 if (ctxt->error != NULL)
5565 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005566 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005567 ctxt->nbErrors++;
5568 }
5569 }
5570
Daniel Veillard2df2de22003-02-17 23:34:33 +00005571 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005572 }
5573#ifdef DEBUG
5574 xmlGenericError(xmlGenericErrorContext,
5575 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5576 choiceOrInterleave);
5577#endif
5578 if (choiceOrInterleave == -1)
5579 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005580 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005581 if (cur == NULL)
5582 return;
5583 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005584 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005585 else
5586 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005587 cur->content = grammar->start;
5588 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005589 if (choiceOrInterleave == 0) {
5590 if (ctxt->interleaves == NULL)
5591 ctxt->interleaves = xmlHashCreate(10);
5592 if (ctxt->interleaves == NULL) {
5593 if (ctxt->error != NULL)
5594 ctxt->error(ctxt->userData,
5595 "Failed to create interleaves hash table\n");
5596 ctxt->nbErrors++;
5597 } else {
5598 char tmpname[32];
5599
5600 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5601 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5602 if (ctxt->error != NULL)
5603 ctxt->error(ctxt->userData,
5604 "Failed to add %s to hash table\n", tmpname);
5605 ctxt->nbErrors++;
5606 }
5607 }
5608 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005609}
5610
5611/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005612 * xmlRelaxNGCheckCycles:
5613 * @ctxt: a Relax-NG parser context
5614 * @nodes: grammar children nodes
5615 * @depth: the counter
5616 *
5617 * Check for cycles.
5618 *
5619 * Returns 0 if check passed, and -1 in case of error
5620 */
5621static int
5622xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5623 xmlRelaxNGDefinePtr cur, int depth) {
5624 int ret = 0;
5625
5626 while ((ret == 0) && (cur != NULL)) {
5627 if ((cur->type == XML_RELAXNG_REF) ||
5628 (cur->type == XML_RELAXNG_PARENTREF)) {
5629 if (cur->depth == -1) {
5630 cur->depth = depth;
5631 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5632 cur->depth = -2;
5633 } else if (depth == cur->depth) {
5634 if (ctxt->error != NULL)
5635 ctxt->error(ctxt->userData,
5636 "Detected a cycle in %s references\n", cur->name);
5637 ctxt->nbErrors++;
5638 return(-1);
5639 }
5640 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5641 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5642 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005643 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005644 }
5645 cur = cur->next;
5646 }
5647 return(ret);
5648}
5649
5650/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005651 * xmlRelaxNGTryUnlink:
5652 * @ctxt: a Relax-NG parser context
5653 * @cur: the definition to unlink
5654 * @parent: the parent definition
5655 * @prev: the previous sibling definition
5656 *
5657 * Try to unlink a definition. If not possble make it a NOOP
5658 *
5659 * Returns the new prev definition
5660 */
5661static xmlRelaxNGDefinePtr
5662xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5663 xmlRelaxNGDefinePtr cur,
5664 xmlRelaxNGDefinePtr parent,
5665 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005666 if (prev != NULL) {
5667 prev->next = cur->next;
5668 } else {
5669 if (parent != NULL) {
5670 if (parent->content == cur)
5671 parent->content = cur->next;
5672 else if (parent->attrs == cur)
5673 parent->attrs = cur->next;
5674 else if (parent->nameClass == cur)
5675 parent->nameClass = cur->next;
5676 } else {
5677 cur->type = XML_RELAXNG_NOOP;
5678 prev = cur;
5679 }
5680 }
5681 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005682}
5683
5684/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005685 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005686 * @ctxt: a Relax-NG parser context
5687 * @nodes: grammar children nodes
5688 *
5689 * Check for simplification of empty and notAllowed
5690 */
5691static void
5692xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5693 xmlRelaxNGDefinePtr cur,
5694 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005695 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005696
Daniel Veillardfd573f12003-03-16 17:52:32 +00005697 while (cur != NULL) {
5698 if ((cur->type == XML_RELAXNG_REF) ||
5699 (cur->type == XML_RELAXNG_PARENTREF)) {
5700 if (cur->depth != -3) {
5701 cur->depth = -3;
5702 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005703 }
5704 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005705 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005706 if ((parent != NULL) &&
5707 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5708 (parent->type == XML_RELAXNG_LIST) ||
5709 (parent->type == XML_RELAXNG_GROUP) ||
5710 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005711 (parent->type == XML_RELAXNG_ONEORMORE) ||
5712 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005713 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005714 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005715 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005716 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005717 (parent->type == XML_RELAXNG_CHOICE)) {
5718 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5719 } else
5720 prev = cur;
5721 } else if (cur->type == XML_RELAXNG_EMPTY){
5722 cur->parent = parent;
5723 if ((parent != NULL) &&
5724 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5725 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005726 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005727 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005728 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005729 if ((parent != NULL) &&
5730 ((parent->type == XML_RELAXNG_GROUP) ||
5731 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5732 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5733 } else
5734 prev = cur;
5735 } else {
5736 cur->parent = parent;
5737 if (cur->content != NULL)
5738 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005739 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005740 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5741 if (cur->nameClass != NULL)
5742 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5743 /*
5744 * This may result in a simplification
5745 */
5746 if ((cur->type == XML_RELAXNG_GROUP) ||
5747 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5748 if (cur->content == NULL)
5749 cur->type = XML_RELAXNG_EMPTY;
5750 else if (cur->content->next == NULL) {
5751 if ((parent == NULL) && (prev == NULL)) {
5752 cur->type = XML_RELAXNG_NOOP;
5753 } else if (prev == NULL) {
5754 parent->content = cur->content;
5755 cur->content->next = cur->next;
5756 cur = cur->content;
5757 } else {
5758 cur->content->next = cur->next;
5759 prev->next = cur->content;
5760 cur = cur->content;
5761 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005762 }
5763 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005764 /*
5765 * the current node may have been transformed back
5766 */
5767 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5768 (cur->content != NULL) &&
5769 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5770 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5771 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5772 if ((parent != NULL) &&
5773 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5774 (parent->type == XML_RELAXNG_LIST) ||
5775 (parent->type == XML_RELAXNG_GROUP) ||
5776 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5777 (parent->type == XML_RELAXNG_ONEORMORE) ||
5778 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5779 parent->type = XML_RELAXNG_NOT_ALLOWED;
5780 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005781 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005782 if ((parent != NULL) &&
5783 (parent->type == XML_RELAXNG_CHOICE)) {
5784 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5785 } else
5786 prev = cur;
5787 } else if (cur->type == XML_RELAXNG_EMPTY){
5788 if ((parent != NULL) &&
5789 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5790 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5791 parent->type = XML_RELAXNG_EMPTY;
5792 break;
5793 }
5794 if ((parent != NULL) &&
5795 ((parent->type == XML_RELAXNG_GROUP) ||
5796 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5797 (parent->type == XML_RELAXNG_CHOICE))) {
5798 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5799 } else
5800 prev = cur;
5801 } else {
5802 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005803 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005804 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005805 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005806 }
5807}
5808
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005809/**
5810 * xmlRelaxNGGroupContentType:
5811 * @ct1: the first content type
5812 * @ct2: the second content type
5813 *
5814 * Try to group 2 content types
5815 *
5816 * Returns the content type
5817 */
5818static xmlRelaxNGContentType
5819xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5820 xmlRelaxNGContentType ct2) {
5821 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5822 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5823 return(XML_RELAXNG_CONTENT_ERROR);
5824 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5825 return(ct2);
5826 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5827 return(ct1);
5828 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5829 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5830 return(XML_RELAXNG_CONTENT_COMPLEX);
5831 return(XML_RELAXNG_CONTENT_ERROR);
5832}
5833
5834/**
5835 * xmlRelaxNGMaxContentType:
5836 * @ct1: the first content type
5837 * @ct2: the second content type
5838 *
5839 * Compute the max content-type
5840 *
5841 * Returns the content type
5842 */
5843static xmlRelaxNGContentType
5844xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5845 xmlRelaxNGContentType ct2) {
5846 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5847 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5848 return(XML_RELAXNG_CONTENT_ERROR);
5849 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5850 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5851 return(XML_RELAXNG_CONTENT_SIMPLE);
5852 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5853 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5854 return(XML_RELAXNG_CONTENT_COMPLEX);
5855 return(XML_RELAXNG_CONTENT_EMPTY);
5856}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005857
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005858/**
5859 * xmlRelaxNGCheckRules:
5860 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005861 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005862 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005863 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005864 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005865 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005866 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005867 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005868 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005869static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005870xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5871 xmlRelaxNGDefinePtr cur, int flags,
5872 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005873 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005874 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005875
Daniel Veillardfd573f12003-03-16 17:52:32 +00005876 while (cur != NULL) {
5877 ret = XML_RELAXNG_CONTENT_EMPTY;
5878 if ((cur->type == XML_RELAXNG_REF) ||
5879 (cur->type == XML_RELAXNG_PARENTREF)) {
5880 if (flags & XML_RELAXNG_IN_LIST) {
5881 if (ctxt->error != NULL)
5882 ctxt->error(ctxt->userData,
5883 "Found forbidden pattern list//ref\n");
5884 ctxt->nbErrors++;
5885 }
5886 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5887 if (ctxt->error != NULL)
5888 ctxt->error(ctxt->userData,
5889 "Found forbidden pattern data/except//ref\n");
5890 ctxt->nbErrors++;
5891 }
5892 if (cur->depth > -4) {
5893 cur->depth = -4;
5894 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5895 flags, cur->type);
5896 cur->depth = ret - 15 ;
5897 } else if (cur->depth == -4) {
5898 ret = XML_RELAXNG_CONTENT_COMPLEX;
5899 } else {
5900 ret = (xmlRelaxNGContentType) cur->depth + 15;
5901 }
5902 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5903 /*
5904 * The 7.3 Attribute derivation rule for groups is plugged there
5905 */
5906 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5907 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5908 if (ctxt->error != NULL)
5909 ctxt->error(ctxt->userData,
5910 "Found forbidden pattern data/except//element(ref)\n");
5911 ctxt->nbErrors++;
5912 }
5913 if (flags & XML_RELAXNG_IN_LIST) {
5914 if (ctxt->error != NULL)
5915 ctxt->error(ctxt->userData,
5916 "Found forbidden pattern list//element(ref)\n");
5917 ctxt->nbErrors++;
5918 }
5919 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5920 if (ctxt->error != NULL)
5921 ctxt->error(ctxt->userData,
5922 "Found forbidden pattern attribute//element(ref)\n");
5923 ctxt->nbErrors++;
5924 }
5925 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5926 if (ctxt->error != NULL)
5927 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005928 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005929 ctxt->nbErrors++;
5930 }
5931 /*
5932 * reset since in the simple form elements are only child
5933 * of grammar/define
5934 */
5935 nflags = 0;
5936 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5937 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5938 if (ctxt->error != NULL)
5939 ctxt->error(ctxt->userData,
5940 "Element %s attributes have a content type error\n",
5941 cur->name);
5942 ctxt->nbErrors++;
5943 }
5944 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5945 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5946 if (ctxt->error != NULL)
5947 ctxt->error(ctxt->userData,
5948 "Element %s has a content type error\n",
5949 cur->name);
5950 ctxt->nbErrors++;
5951 } else {
5952 ret = XML_RELAXNG_CONTENT_COMPLEX;
5953 }
5954 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5955 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5956 if (ctxt->error != NULL)
5957 ctxt->error(ctxt->userData,
5958 "Found forbidden pattern attribute//attribute\n");
5959 ctxt->nbErrors++;
5960 }
5961 if (flags & XML_RELAXNG_IN_LIST) {
5962 if (ctxt->error != NULL)
5963 ctxt->error(ctxt->userData,
5964 "Found forbidden pattern list//attribute\n");
5965 ctxt->nbErrors++;
5966 }
5967 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5968 if (ctxt->error != NULL)
5969 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005970 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005971 ctxt->nbErrors++;
5972 }
5973 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5974 if (ctxt->error != NULL)
5975 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005976 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005977 ctxt->nbErrors++;
5978 }
5979 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5980 if (ctxt->error != NULL)
5981 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005982 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005983 ctxt->nbErrors++;
5984 }
5985 if (flags & XML_RELAXNG_IN_START) {
5986 if (ctxt->error != NULL)
5987 ctxt->error(ctxt->userData,
5988 "Found forbidden pattern start//attribute\n");
5989 ctxt->nbErrors++;
5990 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005991 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5992 if (cur->ns == NULL) {
5993 if (ctxt->error != NULL)
5994 ctxt->error(ctxt->userData,
5995 "Found anyName attribute without oneOrMore ancestor\n");
5996 ctxt->nbErrors++;
5997 } else {
5998 if (ctxt->error != NULL)
5999 ctxt->error(ctxt->userData,
6000 "Found nsName attribute without oneOrMore ancestor\n");
6001 ctxt->nbErrors++;
6002 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00006003 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006004 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6005 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6006 ret = XML_RELAXNG_CONTENT_EMPTY;
6007 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6008 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6009 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6010 if (ctxt->error != NULL)
6011 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006012 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006013 ctxt->nbErrors++;
6014 }
6015 if (flags & XML_RELAXNG_IN_START) {
6016 if (ctxt->error != NULL)
6017 ctxt->error(ctxt->userData,
6018 "Found forbidden pattern start//oneOrMore\n");
6019 ctxt->nbErrors++;
6020 }
6021 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6022 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6023 ret = xmlRelaxNGGroupContentType(ret, ret);
6024 } else if (cur->type == XML_RELAXNG_LIST) {
6025 if (flags & XML_RELAXNG_IN_LIST) {
6026 if (ctxt->error != NULL)
6027 ctxt->error(ctxt->userData,
6028 "Found forbidden pattern list//list\n");
6029 ctxt->nbErrors++;
6030 }
6031 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6032 if (ctxt->error != NULL)
6033 ctxt->error(ctxt->userData,
6034 "Found forbidden pattern data/except//list\n");
6035 ctxt->nbErrors++;
6036 }
6037 if (flags & XML_RELAXNG_IN_START) {
6038 if (ctxt->error != NULL)
6039 ctxt->error(ctxt->userData,
6040 "Found forbidden pattern start//list\n");
6041 ctxt->nbErrors++;
6042 }
6043 nflags = flags | XML_RELAXNG_IN_LIST;
6044 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6045 } else if (cur->type == XML_RELAXNG_GROUP) {
6046 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6047 if (ctxt->error != NULL)
6048 ctxt->error(ctxt->userData,
6049 "Found forbidden pattern data/except//group\n");
6050 ctxt->nbErrors++;
6051 }
6052 if (flags & XML_RELAXNG_IN_START) {
6053 if (ctxt->error != NULL)
6054 ctxt->error(ctxt->userData,
6055 "Found forbidden pattern start//group\n");
6056 ctxt->nbErrors++;
6057 }
6058 if (flags & XML_RELAXNG_IN_ONEORMORE)
6059 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6060 else
6061 nflags = flags;
6062 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6063 /*
6064 * The 7.3 Attribute derivation rule for groups is plugged there
6065 */
6066 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6067 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6068 if (flags & XML_RELAXNG_IN_LIST) {
6069 if (ctxt->error != NULL)
6070 ctxt->error(ctxt->userData,
6071 "Found forbidden pattern list//interleave\n");
6072 ctxt->nbErrors++;
6073 }
6074 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6075 if (ctxt->error != NULL)
6076 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006077 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006078 ctxt->nbErrors++;
6079 }
6080 if (flags & XML_RELAXNG_IN_START) {
6081 if (ctxt->error != NULL)
6082 ctxt->error(ctxt->userData,
6083 "Found forbidden pattern start//interleave\n");
6084 ctxt->nbErrors++;
6085 }
6086 if (flags & XML_RELAXNG_IN_ONEORMORE)
6087 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6088 else
6089 nflags = flags;
6090 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6091 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6092 if ((cur->parent != NULL) &&
6093 (cur->parent->type == XML_RELAXNG_DATATYPE))
6094 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6095 else
6096 nflags = flags;
6097 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6098 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6099 if (flags & XML_RELAXNG_IN_START) {
6100 if (ctxt->error != NULL)
6101 ctxt->error(ctxt->userData,
6102 "Found forbidden pattern start//data\n");
6103 ctxt->nbErrors++;
6104 }
6105 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6106 ret = XML_RELAXNG_CONTENT_SIMPLE;
6107 } else if (cur->type == XML_RELAXNG_VALUE) {
6108 if (flags & XML_RELAXNG_IN_START) {
6109 if (ctxt->error != NULL)
6110 ctxt->error(ctxt->userData,
6111 "Found forbidden pattern start//value\n");
6112 ctxt->nbErrors++;
6113 }
6114 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6115 ret = XML_RELAXNG_CONTENT_SIMPLE;
6116 } else if (cur->type == XML_RELAXNG_TEXT) {
6117 if (flags & XML_RELAXNG_IN_LIST) {
6118 if (ctxt->error != NULL)
6119 ctxt->error(ctxt->userData,
6120 "Found forbidden pattern list//text\n");
6121 ctxt->nbErrors++;
6122 }
6123 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6124 if (ctxt->error != NULL)
6125 ctxt->error(ctxt->userData,
6126 "Found forbidden pattern data/except//text\n");
6127 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//text\n");
6133 ctxt->nbErrors++;
6134 }
6135 ret = XML_RELAXNG_CONTENT_COMPLEX;
6136 } else if (cur->type == XML_RELAXNG_EMPTY) {
6137 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6138 if (ctxt->error != NULL)
6139 ctxt->error(ctxt->userData,
6140 "Found forbidden pattern data/except//empty\n");
6141 ctxt->nbErrors++;
6142 }
6143 if (flags & XML_RELAXNG_IN_START) {
6144 if (ctxt->error != NULL)
6145 ctxt->error(ctxt->userData,
6146 "Found forbidden pattern start//empty\n");
6147 ctxt->nbErrors++;
6148 }
6149 ret = XML_RELAXNG_CONTENT_EMPTY;
6150 } else if (cur->type == XML_RELAXNG_CHOICE) {
6151 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6152 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6153 } else {
6154 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6155 }
6156 cur = cur->next;
6157 if (ptype == XML_RELAXNG_GROUP) {
6158 val = xmlRelaxNGGroupContentType(val, ret);
6159 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6160 tmp = xmlRelaxNGGroupContentType(val, ret);
6161 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6162 tmp = xmlRelaxNGMaxContentType(val, ret);
6163 } else if (ptype == XML_RELAXNG_CHOICE) {
6164 val = xmlRelaxNGMaxContentType(val, ret);
6165 } else if (ptype == XML_RELAXNG_LIST) {
6166 val = XML_RELAXNG_CONTENT_SIMPLE;
6167 } else if (ptype == XML_RELAXNG_EXCEPT) {
6168 if (ret == XML_RELAXNG_CONTENT_ERROR)
6169 val = XML_RELAXNG_CONTENT_ERROR;
6170 else
6171 val = XML_RELAXNG_CONTENT_SIMPLE;
6172 } else {
6173 val = xmlRelaxNGGroupContentType(val, ret);
6174 }
6175
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006176 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006177 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006178}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006179
6180/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006181 * xmlRelaxNGParseGrammar:
6182 * @ctxt: a Relax-NG parser context
6183 * @nodes: grammar children nodes
6184 *
6185 * parse a Relax-NG <grammar> node
6186 *
6187 * Returns the internal xmlRelaxNGGrammarPtr built or
6188 * NULL in case of error
6189 */
6190static xmlRelaxNGGrammarPtr
6191xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6192 xmlRelaxNGGrammarPtr ret, tmp, old;
6193
Daniel Veillardc482e262003-02-26 14:48:48 +00006194#ifdef DEBUG_GRAMMAR
6195 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6196#endif
6197
Daniel Veillard6eadf632003-01-23 18:29:16 +00006198 ret = xmlRelaxNGNewGrammar(ctxt);
6199 if (ret == NULL)
6200 return(NULL);
6201
6202 /*
6203 * Link the new grammar in the tree
6204 */
6205 ret->parent = ctxt->grammar;
6206 if (ctxt->grammar != NULL) {
6207 tmp = ctxt->grammar->children;
6208 if (tmp == NULL) {
6209 ctxt->grammar->children = ret;
6210 } else {
6211 while (tmp->next != NULL)
6212 tmp = tmp->next;
6213 tmp->next = ret;
6214 }
6215 }
6216
6217 old = ctxt->grammar;
6218 ctxt->grammar = ret;
6219 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6220 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006221 if (ctxt->grammar == NULL) {
6222 if (ctxt->error != NULL)
6223 ctxt->error(ctxt->userData,
6224 "Failed to parse <grammar> content\n");
6225 ctxt->nbErrors++;
6226 } else if (ctxt->grammar->start == NULL) {
6227 if (ctxt->error != NULL)
6228 ctxt->error(ctxt->userData,
6229 "Element <grammar> has no <start>\n");
6230 ctxt->nbErrors++;
6231 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006232
6233 /*
6234 * Apply 4.17 mergingd rules to defines and starts
6235 */
6236 xmlRelaxNGCombineStart(ctxt, ret);
6237 if (ret->defs != NULL) {
6238 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6239 ctxt);
6240 }
6241
6242 /*
6243 * link together defines and refs in this grammar
6244 */
6245 if (ret->refs != NULL) {
6246 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6247 ctxt);
6248 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006249
Daniel Veillard6eadf632003-01-23 18:29:16 +00006250 ctxt->grammar = old;
6251 return(ret);
6252}
6253
6254/**
6255 * xmlRelaxNGParseDocument:
6256 * @ctxt: a Relax-NG parser context
6257 * @node: the root node of the RelaxNG schema
6258 *
6259 * parse a Relax-NG definition resource and build an internal
6260 * xmlRelaxNG struture which can be used to validate instances.
6261 *
6262 * Returns the internal XML RelaxNG structure built or
6263 * NULL in case of error
6264 */
6265static xmlRelaxNGPtr
6266xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6267 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006268 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006269 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006270
6271 if ((ctxt == NULL) || (node == NULL))
6272 return (NULL);
6273
6274 schema = xmlRelaxNGNewRelaxNG(ctxt);
6275 if (schema == NULL)
6276 return(NULL);
6277
Daniel Veillard276be4a2003-01-24 01:03:34 +00006278 olddefine = ctxt->define;
6279 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006280 if (IS_RELAXNG(node, "grammar")) {
6281 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6282 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00006283 xmlRelaxNGGrammarPtr tmp, ret;
6284
6285 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006286 if (schema->topgrammar == NULL) {
6287 return(schema);
6288 }
Daniel Veillardc482e262003-02-26 14:48:48 +00006289 /*
6290 * Link the new grammar in the tree
6291 */
6292 ret->parent = ctxt->grammar;
6293 if (ctxt->grammar != NULL) {
6294 tmp = ctxt->grammar->children;
6295 if (tmp == NULL) {
6296 ctxt->grammar->children = ret;
6297 } else {
6298 while (tmp->next != NULL)
6299 tmp = tmp->next;
6300 tmp->next = ret;
6301 }
6302 }
Daniel Veillarde431a272003-01-29 23:02:33 +00006303 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00006304 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006305 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00006306 if (old != NULL)
6307 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006308 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006309 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006310 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006311 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006312 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006313 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6314 while ((schema->topgrammar->start != NULL) &&
6315 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6316 (schema->topgrammar->start->next != NULL))
6317 schema->topgrammar->start = schema->topgrammar->start->content;
6318 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6319 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006320 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006321 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006322
6323#ifdef DEBUG
6324 if (schema == NULL)
6325 xmlGenericError(xmlGenericErrorContext,
6326 "xmlRelaxNGParseDocument() failed\n");
6327#endif
6328
6329 return (schema);
6330}
6331
6332/************************************************************************
6333 * *
6334 * Reading RelaxNGs *
6335 * *
6336 ************************************************************************/
6337
6338/**
6339 * xmlRelaxNGNewParserCtxt:
6340 * @URL: the location of the schema
6341 *
6342 * Create an XML RelaxNGs parse context for that file/resource expected
6343 * to contain an XML RelaxNGs file.
6344 *
6345 * Returns the parser context or NULL in case of error
6346 */
6347xmlRelaxNGParserCtxtPtr
6348xmlRelaxNGNewParserCtxt(const char *URL) {
6349 xmlRelaxNGParserCtxtPtr ret;
6350
6351 if (URL == NULL)
6352 return(NULL);
6353
6354 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6355 if (ret == NULL) {
6356 xmlGenericError(xmlGenericErrorContext,
6357 "Failed to allocate new schama parser context for %s\n", URL);
6358 return (NULL);
6359 }
6360 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6361 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006362 ret->error = xmlGenericError;
6363 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006364 return (ret);
6365}
6366
6367/**
6368 * xmlRelaxNGNewMemParserCtxt:
6369 * @buffer: a pointer to a char array containing the schemas
6370 * @size: the size of the array
6371 *
6372 * Create an XML RelaxNGs parse context for that memory buffer expected
6373 * to contain an XML RelaxNGs file.
6374 *
6375 * Returns the parser context or NULL in case of error
6376 */
6377xmlRelaxNGParserCtxtPtr
6378xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6379 xmlRelaxNGParserCtxtPtr ret;
6380
6381 if ((buffer == NULL) || (size <= 0))
6382 return(NULL);
6383
6384 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6385 if (ret == NULL) {
6386 xmlGenericError(xmlGenericErrorContext,
6387 "Failed to allocate new schama parser context\n");
6388 return (NULL);
6389 }
6390 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6391 ret->buffer = buffer;
6392 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006393 ret->error = xmlGenericError;
6394 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006395 return (ret);
6396}
6397
6398/**
6399 * xmlRelaxNGFreeParserCtxt:
6400 * @ctxt: the schema parser context
6401 *
6402 * Free the resources associated to the schema parser context
6403 */
6404void
6405xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6406 if (ctxt == NULL)
6407 return;
6408 if (ctxt->URL != NULL)
6409 xmlFree(ctxt->URL);
6410 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006411 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006412 if (ctxt->interleaves != NULL)
6413 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006414 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006415 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006416 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006417 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006418 if (ctxt->docTab != NULL)
6419 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006420 if (ctxt->incTab != NULL)
6421 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006422 if (ctxt->defTab != NULL) {
6423 int i;
6424
6425 for (i = 0;i < ctxt->defNr;i++)
6426 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6427 xmlFree(ctxt->defTab);
6428 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006429 xmlFree(ctxt);
6430}
6431
Daniel Veillard6eadf632003-01-23 18:29:16 +00006432/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006433 * xmlRelaxNGNormExtSpace:
6434 * @value: a value
6435 *
6436 * Removes the leading and ending spaces of the value
6437 * The string is modified "in situ"
6438 */
6439static void
6440xmlRelaxNGNormExtSpace(xmlChar *value) {
6441 xmlChar *start = value;
6442 xmlChar *cur = value;
6443 if (value == NULL)
6444 return;
6445
6446 while (IS_BLANK(*cur)) cur++;
6447 if (cur == start) {
6448 do {
6449 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6450 if (*cur == 0)
6451 return;
6452 start = cur;
6453 while (IS_BLANK(*cur)) cur++;
6454 if (*cur == 0) {
6455 *start = 0;
6456 return;
6457 }
6458 } while (1);
6459 } else {
6460 do {
6461 while ((*cur != 0) && (!IS_BLANK(*cur)))
6462 *start++ = *cur++;
6463 if (*cur == 0) {
6464 *start = 0;
6465 return;
6466 }
6467 /* don't try to normalize the inner spaces */
6468 while (IS_BLANK(*cur)) cur++;
6469 *start++ = *cur++;
6470 if (*cur == 0) {
6471 *start = 0;
6472 return;
6473 }
6474 } while (1);
6475 }
6476}
6477
6478/**
6479 * xmlRelaxNGCheckAttributes:
6480 * @ctxt: a Relax-NG parser context
6481 * @node: a Relax-NG node
6482 *
6483 * Check all the attributes on the given node
6484 */
6485static void
6486xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6487 xmlAttrPtr cur, next;
6488
6489 cur = node->properties;
6490 while (cur != NULL) {
6491 next = cur->next;
6492 if ((cur->ns == NULL) ||
6493 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6494 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6495 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6496 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6497 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6498 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006499 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006500 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6501 if (ctxt->error != NULL)
6502 ctxt->error(ctxt->userData,
6503 "Attribute %s is not allowed on %s\n",
6504 cur->name, node->name);
6505 ctxt->nbErrors++;
6506 }
6507 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6508 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6509 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6510 if (ctxt->error != NULL)
6511 ctxt->error(ctxt->userData,
6512 "Attribute %s is not allowed on %s\n",
6513 cur->name, node->name);
6514 ctxt->nbErrors++;
6515 }
6516 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6517 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6518 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6519 if (ctxt->error != NULL)
6520 ctxt->error(ctxt->userData,
6521 "Attribute %s is not allowed on %s\n",
6522 cur->name, node->name);
6523 ctxt->nbErrors++;
6524 }
6525 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6526 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6527 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6528 if (ctxt->error != NULL)
6529 ctxt->error(ctxt->userData,
6530 "Attribute %s is not allowed on %s\n",
6531 cur->name, node->name);
6532 ctxt->nbErrors++;
6533 }
6534 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6535 xmlChar *val;
6536 xmlURIPtr uri;
6537
6538 val = xmlNodeListGetString(node->doc, cur->children, 1);
6539 if (val != NULL) {
6540 if (val[0] != 0) {
6541 uri = xmlParseURI((const char *) val);
6542 if (uri == NULL) {
6543 if (ctxt->error != NULL)
6544 ctxt->error(ctxt->userData,
6545 "Attribute %s contains invalid URI %s\n",
6546 cur->name, val);
6547 ctxt->nbErrors++;
6548 } else {
6549 if (uri->scheme == NULL) {
6550 if (ctxt->error != NULL)
6551 ctxt->error(ctxt->userData,
6552 "Attribute %s URI %s is not absolute\n",
6553 cur->name, val);
6554 ctxt->nbErrors++;
6555 }
6556 if (uri->fragment != NULL) {
6557 if (ctxt->error != NULL)
6558 ctxt->error(ctxt->userData,
6559 "Attribute %s URI %s has a fragment ID\n",
6560 cur->name, val);
6561 ctxt->nbErrors++;
6562 }
6563 xmlFreeURI(uri);
6564 }
6565 }
6566 xmlFree(val);
6567 }
6568 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6569 if (ctxt->error != NULL)
6570 ctxt->error(ctxt->userData,
6571 "Unknown attribute %s on %s\n",
6572 cur->name, node->name);
6573 ctxt->nbErrors++;
6574 }
6575 }
6576 cur = next;
6577 }
6578}
6579
6580/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006581 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006582 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006583 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006584 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006585 * Cleanup the subtree from unwanted nodes for parsing, resolve
6586 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006587 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006588static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006589xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006590 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006591
Daniel Veillard6eadf632003-01-23 18:29:16 +00006592 delete = NULL;
6593 cur = root;
6594 while (cur != NULL) {
6595 if (delete != NULL) {
6596 xmlUnlinkNode(delete);
6597 xmlFreeNode(delete);
6598 delete = NULL;
6599 }
6600 if (cur->type == XML_ELEMENT_NODE) {
6601 /*
6602 * Simplification 4.1. Annotations
6603 */
6604 if ((cur->ns == NULL) ||
6605 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006606 if ((cur->parent != NULL) &&
6607 (cur->parent->type == XML_ELEMENT_NODE) &&
6608 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6609 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6610 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6611 if (ctxt->error != NULL)
6612 ctxt->error(ctxt->userData,
6613 "element %s doesn't allow foreign elements\n",
6614 cur->parent->name);
6615 ctxt->nbErrors++;
6616 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006617 delete = cur;
6618 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006619 } else {
6620 xmlRelaxNGCleanupAttributes(ctxt, cur);
6621 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6622 xmlChar *href, *ns, *base, *URL;
6623 xmlRelaxNGDocumentPtr docu;
6624 xmlNodePtr tmp;
6625
6626 ns = xmlGetProp(cur, BAD_CAST "ns");
6627 if (ns == NULL) {
6628 tmp = cur->parent;
6629 while ((tmp != NULL) &&
6630 (tmp->type == XML_ELEMENT_NODE)) {
6631 ns = xmlGetProp(tmp, BAD_CAST "ns");
6632 if (ns != NULL)
6633 break;
6634 tmp = tmp->parent;
6635 }
6636 }
6637 href = xmlGetProp(cur, BAD_CAST "href");
6638 if (href == NULL) {
6639 if (ctxt->error != NULL)
6640 ctxt->error(ctxt->userData,
6641 "xmlRelaxNGParse: externalRef has no href attribute\n");
6642 ctxt->nbErrors++;
6643 delete = cur;
6644 goto skip_children;
6645 }
6646 base = xmlNodeGetBase(cur->doc, cur);
6647 URL = xmlBuildURI(href, base);
6648 if (URL == NULL) {
6649 if (ctxt->error != NULL)
6650 ctxt->error(ctxt->userData,
6651 "Failed to compute URL for externalRef %s\n", href);
6652 ctxt->nbErrors++;
6653 if (href != NULL)
6654 xmlFree(href);
6655 if (base != NULL)
6656 xmlFree(base);
6657 delete = cur;
6658 goto skip_children;
6659 }
6660 if (href != NULL)
6661 xmlFree(href);
6662 if (base != NULL)
6663 xmlFree(base);
6664 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6665 if (docu == NULL) {
6666 if (ctxt->error != NULL)
6667 ctxt->error(ctxt->userData,
6668 "Failed to load externalRef %s\n", URL);
6669 ctxt->nbErrors++;
6670 xmlFree(URL);
6671 delete = cur;
6672 goto skip_children;
6673 }
6674 if (ns != NULL)
6675 xmlFree(ns);
6676 xmlFree(URL);
6677 cur->_private = docu;
6678 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6679 xmlChar *href, *ns, *base, *URL;
6680 xmlRelaxNGIncludePtr incl;
6681 xmlNodePtr tmp;
6682
6683 href = xmlGetProp(cur, BAD_CAST "href");
6684 if (href == NULL) {
6685 if (ctxt->error != NULL)
6686 ctxt->error(ctxt->userData,
6687 "xmlRelaxNGParse: include has no href attribute\n");
6688 ctxt->nbErrors++;
6689 delete = cur;
6690 goto skip_children;
6691 }
6692 base = xmlNodeGetBase(cur->doc, cur);
6693 URL = xmlBuildURI(href, base);
6694 if (URL == NULL) {
6695 if (ctxt->error != NULL)
6696 ctxt->error(ctxt->userData,
6697 "Failed to compute URL for include %s\n", href);
6698 ctxt->nbErrors++;
6699 if (href != NULL)
6700 xmlFree(href);
6701 if (base != NULL)
6702 xmlFree(base);
6703 delete = cur;
6704 goto skip_children;
6705 }
6706 if (href != NULL)
6707 xmlFree(href);
6708 if (base != NULL)
6709 xmlFree(base);
6710 ns = xmlGetProp(cur, BAD_CAST "ns");
6711 if (ns == NULL) {
6712 tmp = cur->parent;
6713 while ((tmp != NULL) &&
6714 (tmp->type == XML_ELEMENT_NODE)) {
6715 ns = xmlGetProp(tmp, BAD_CAST "ns");
6716 if (ns != NULL)
6717 break;
6718 tmp = tmp->parent;
6719 }
6720 }
6721 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6722 if (ns != NULL)
6723 xmlFree(ns);
6724 if (incl == NULL) {
6725 if (ctxt->error != NULL)
6726 ctxt->error(ctxt->userData,
6727 "Failed to load include %s\n", URL);
6728 ctxt->nbErrors++;
6729 xmlFree(URL);
6730 delete = cur;
6731 goto skip_children;
6732 }
6733 xmlFree(URL);
6734 cur->_private = incl;
6735 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6736 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6737 xmlChar *name, *ns;
6738 xmlNodePtr text = NULL;
6739
6740 /*
6741 * Simplification 4.8. name attribute of element
6742 * and attribute elements
6743 */
6744 name = xmlGetProp(cur, BAD_CAST "name");
6745 if (name != NULL) {
6746 if (cur->children == NULL) {
6747 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6748 name);
6749 } else {
6750 xmlNodePtr node;
6751 node = xmlNewNode(cur->ns, BAD_CAST "name");
6752 if (node != NULL) {
6753 xmlAddPrevSibling(cur->children, node);
6754 text = xmlNewText(name);
6755 xmlAddChild(node, text);
6756 text = node;
6757 }
6758 }
6759 if (text == NULL) {
6760 if (ctxt->error != NULL)
6761 ctxt->error(ctxt->userData,
6762 "Failed to create a name %s element\n", name);
6763 ctxt->nbErrors++;
6764 }
6765 xmlUnsetProp(cur, BAD_CAST "name");
6766 xmlFree(name);
6767 ns = xmlGetProp(cur, BAD_CAST "ns");
6768 if (ns != NULL) {
6769 if (text != NULL) {
6770 xmlSetProp(text, BAD_CAST "ns", ns);
6771 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6772 }
6773 xmlFree(ns);
6774 } else if (xmlStrEqual(cur->name,
6775 BAD_CAST "attribute")) {
6776 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6777 }
6778 }
6779 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6780 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6781 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6782 /*
6783 * Simplification 4.8. name attribute of element
6784 * and attribute elements
6785 */
6786 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6787 xmlNodePtr node;
6788 xmlChar *ns = NULL;
6789
6790 node = cur->parent;
6791 while ((node != NULL) &&
6792 (node->type == XML_ELEMENT_NODE)) {
6793 ns = xmlGetProp(node, BAD_CAST "ns");
6794 if (ns != NULL) {
6795 break;
6796 }
6797 node = node->parent;
6798 }
6799 if (ns == NULL) {
6800 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6801 } else {
6802 xmlSetProp(cur, BAD_CAST "ns", ns);
6803 xmlFree(ns);
6804 }
6805 }
6806 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6807 xmlChar *name, *local, *prefix;
6808
6809 /*
6810 * Simplification: 4.10. QNames
6811 */
6812 name = xmlNodeGetContent(cur);
6813 if (name != NULL) {
6814 local = xmlSplitQName2(name, &prefix);
6815 if (local != NULL) {
6816 xmlNsPtr ns;
6817
6818 ns = xmlSearchNs(cur->doc, cur, prefix);
6819 if (ns == NULL) {
6820 if (ctxt->error != NULL)
6821 ctxt->error(ctxt->userData,
6822 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6823 ctxt->nbErrors++;
6824 } else {
6825 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6826 xmlNodeSetContent(cur, local);
6827 }
6828 xmlFree(local);
6829 xmlFree(prefix);
6830 }
6831 xmlFree(name);
6832 }
6833 }
6834 /*
6835 * 4.16
6836 */
6837 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6838 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6839 if (ctxt->error != NULL)
6840 ctxt->error(ctxt->userData,
6841 "Found nsName/except//nsName forbidden construct\n");
6842 ctxt->nbErrors++;
6843 }
6844 }
6845 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6846 (cur != root)) {
6847 int oldflags = ctxt->flags;
6848
6849 /*
6850 * 4.16
6851 */
6852 if ((cur->parent != NULL) &&
6853 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6854 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6855 xmlRelaxNGCleanupTree(ctxt, cur);
6856 ctxt->flags = oldflags;
6857 goto skip_children;
6858 } else if ((cur->parent != NULL) &&
6859 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6860 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6861 xmlRelaxNGCleanupTree(ctxt, cur);
6862 ctxt->flags = oldflags;
6863 goto skip_children;
6864 }
6865 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6866 /*
6867 * 4.16
6868 */
6869 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6870 if (ctxt->error != NULL)
6871 ctxt->error(ctxt->userData,
6872 "Found anyName/except//anyName forbidden construct\n");
6873 ctxt->nbErrors++;
6874 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6875 if (ctxt->error != NULL)
6876 ctxt->error(ctxt->userData,
6877 "Found nsName/except//anyName forbidden construct\n");
6878 ctxt->nbErrors++;
6879 }
6880 }
6881 /*
6882 * Thisd is not an else since "include" is transformed
6883 * into a div
6884 */
6885 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6886 xmlChar *ns;
6887 xmlNodePtr child, ins, tmp;
6888
6889 /*
6890 * implements rule 4.11
6891 */
6892
6893 ns = xmlGetProp(cur, BAD_CAST "ns");
6894
6895 child = cur->children;
6896 ins = cur;
6897 while (child != NULL) {
6898 if (ns != NULL) {
6899 if (!xmlHasProp(child, BAD_CAST "ns")) {
6900 xmlSetProp(child, BAD_CAST "ns", ns);
6901 }
6902 }
6903 tmp = child->next;
6904 xmlUnlinkNode(child);
6905 ins = xmlAddNextSibling(ins, child);
6906 child = tmp;
6907 }
6908 if (ns != NULL)
6909 xmlFree(ns);
6910 delete = cur;
6911 goto skip_children;
6912 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006913 }
6914 }
6915 /*
6916 * Simplification 4.2 whitespaces
6917 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006918 else if ((cur->type == XML_TEXT_NODE) ||
6919 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006920 if (IS_BLANK_NODE(cur)) {
6921 if (cur->parent->type == XML_ELEMENT_NODE) {
6922 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6923 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6924 delete = cur;
6925 } else {
6926 delete = cur;
6927 goto skip_children;
6928 }
6929 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006930 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006931 delete = cur;
6932 goto skip_children;
6933 }
6934
6935 /*
6936 * Skip to next node
6937 */
6938 if (cur->children != NULL) {
6939 if ((cur->children->type != XML_ENTITY_DECL) &&
6940 (cur->children->type != XML_ENTITY_REF_NODE) &&
6941 (cur->children->type != XML_ENTITY_NODE)) {
6942 cur = cur->children;
6943 continue;
6944 }
6945 }
6946skip_children:
6947 if (cur->next != NULL) {
6948 cur = cur->next;
6949 continue;
6950 }
6951
6952 do {
6953 cur = cur->parent;
6954 if (cur == NULL)
6955 break;
6956 if (cur == root) {
6957 cur = NULL;
6958 break;
6959 }
6960 if (cur->next != NULL) {
6961 cur = cur->next;
6962 break;
6963 }
6964 } while (cur != NULL);
6965 }
6966 if (delete != NULL) {
6967 xmlUnlinkNode(delete);
6968 xmlFreeNode(delete);
6969 delete = NULL;
6970 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006971}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006972
Daniel Veillardc5312d72003-02-21 17:14:10 +00006973/**
6974 * xmlRelaxNGCleanupDoc:
6975 * @ctxt: a Relax-NG parser context
6976 * @doc: an xmldocPtr document pointer
6977 *
6978 * Cleanup the document from unwanted nodes for parsing, resolve
6979 * Include and externalRef lookups.
6980 *
6981 * Returns the cleaned up document or NULL in case of error
6982 */
6983static xmlDocPtr
6984xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6985 xmlNodePtr root;
6986
6987 /*
6988 * Extract the root
6989 */
6990 root = xmlDocGetRootElement(doc);
6991 if (root == NULL) {
6992 if (ctxt->error != NULL)
6993 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6994 ctxt->URL);
6995 ctxt->nbErrors++;
6996 return (NULL);
6997 }
6998 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006999 return(doc);
7000}
7001
7002/**
7003 * xmlRelaxNGParse:
7004 * @ctxt: a Relax-NG parser context
7005 *
7006 * parse a schema definition resource and build an internal
7007 * XML Shema struture which can be used to validate instances.
7008 * *WARNING* this interface is highly subject to change
7009 *
7010 * Returns the internal XML RelaxNG structure built from the resource or
7011 * NULL in case of error
7012 */
7013xmlRelaxNGPtr
7014xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7015{
7016 xmlRelaxNGPtr ret = NULL;
7017 xmlDocPtr doc;
7018 xmlNodePtr root;
7019
7020 xmlRelaxNGInitTypes();
7021
7022 if (ctxt == NULL)
7023 return (NULL);
7024
7025 /*
7026 * First step is to parse the input document into an DOM/Infoset
7027 */
7028 if (ctxt->URL != NULL) {
7029 doc = xmlParseFile((const char *) ctxt->URL);
7030 if (doc == NULL) {
7031 if (ctxt->error != NULL)
7032 ctxt->error(ctxt->userData,
7033 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7034 ctxt->nbErrors++;
7035 return (NULL);
7036 }
7037 } else if (ctxt->buffer != NULL) {
7038 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7039 if (doc == NULL) {
7040 if (ctxt->error != NULL)
7041 ctxt->error(ctxt->userData,
7042 "xmlRelaxNGParse: could not parse schemas\n");
7043 ctxt->nbErrors++;
7044 return (NULL);
7045 }
7046 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7047 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7048 } else {
7049 if (ctxt->error != NULL)
7050 ctxt->error(ctxt->userData,
7051 "xmlRelaxNGParse: nothing to parse\n");
7052 ctxt->nbErrors++;
7053 return (NULL);
7054 }
7055 ctxt->document = doc;
7056
7057 /*
7058 * Some preprocessing of the document content
7059 */
7060 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7061 if (doc == NULL) {
7062 xmlFreeDoc(ctxt->document);
7063 ctxt->document = NULL;
7064 return(NULL);
7065 }
7066
Daniel Veillard6eadf632003-01-23 18:29:16 +00007067 /*
7068 * Then do the parsing for good
7069 */
7070 root = xmlDocGetRootElement(doc);
7071 if (root == NULL) {
7072 if (ctxt->error != NULL)
7073 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7074 ctxt->URL);
7075 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007076 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007077 return (NULL);
7078 }
7079 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007080 if (ret == NULL) {
7081 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007082 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007083 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007084
7085 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007086 * Check the ref/defines links
7087 */
7088 /*
7089 * try to preprocess interleaves
7090 */
7091 if (ctxt->interleaves != NULL) {
7092 xmlHashScan(ctxt->interleaves,
7093 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7094 }
7095
7096 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007097 * if there was a parsing error return NULL
7098 */
7099 if (ctxt->nbErrors > 0) {
7100 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007101 ctxt->document = NULL;
7102 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007103 return(NULL);
7104 }
7105
7106 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007107 * try to compile (parts of) the schemas
7108 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00007109 if ((ctxt->grammar != NULL) && (ctxt->grammar->start != NULL)) {
7110 if (ctxt->grammar->start->type != XML_RELAXNG_START) {
7111 xmlRelaxNGDefinePtr def;
7112
7113 def = xmlRelaxNGNewDefine(ctxt, NULL);
7114 if (def != NULL) {
7115 def->type = XML_RELAXNG_START;
7116 def->content = ctxt->grammar->start;
7117 ctxt->grammar->start = def;
7118 }
7119 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007120 xmlRelaxNGTryCompile(ctxt, ctxt->grammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007121 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007122
7123 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007124 * Transfer the pointer for cleanup at the schema level.
7125 */
7126 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007127 ctxt->document = NULL;
7128 ret->documents = ctxt->documents;
7129 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007130
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007131 ret->includes = ctxt->includes;
7132 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007133 ret->defNr = ctxt->defNr;
7134 ret->defTab = ctxt->defTab;
7135 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007136 if (ctxt->idref == 1)
7137 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007138
7139 return (ret);
7140}
7141
7142/**
7143 * xmlRelaxNGSetParserErrors:
7144 * @ctxt: a Relax-NG validation context
7145 * @err: the error callback
7146 * @warn: the warning callback
7147 * @ctx: contextual data for the callbacks
7148 *
7149 * Set the callback functions used to handle errors for a validation context
7150 */
7151void
7152xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7153 xmlRelaxNGValidityErrorFunc err,
7154 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7155 if (ctxt == NULL)
7156 return;
7157 ctxt->error = err;
7158 ctxt->warning = warn;
7159 ctxt->userData = ctx;
7160}
7161/************************************************************************
7162 * *
7163 * Dump back a compiled form *
7164 * *
7165 ************************************************************************/
7166static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7167
7168/**
7169 * xmlRelaxNGDumpDefines:
7170 * @output: the file output
7171 * @defines: a list of define structures
7172 *
7173 * Dump a RelaxNG structure back
7174 */
7175static void
7176xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7177 while (defines != NULL) {
7178 xmlRelaxNGDumpDefine(output, defines);
7179 defines = defines->next;
7180 }
7181}
7182
7183/**
7184 * xmlRelaxNGDumpDefine:
7185 * @output: the file output
7186 * @define: a define structure
7187 *
7188 * Dump a RelaxNG structure back
7189 */
7190static void
7191xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7192 if (define == NULL)
7193 return;
7194 switch(define->type) {
7195 case XML_RELAXNG_EMPTY:
7196 fprintf(output, "<empty/>\n");
7197 break;
7198 case XML_RELAXNG_NOT_ALLOWED:
7199 fprintf(output, "<notAllowed/>\n");
7200 break;
7201 case XML_RELAXNG_TEXT:
7202 fprintf(output, "<text/>\n");
7203 break;
7204 case XML_RELAXNG_ELEMENT:
7205 fprintf(output, "<element>\n");
7206 if (define->name != NULL) {
7207 fprintf(output, "<name");
7208 if (define->ns != NULL)
7209 fprintf(output, " ns=\"%s\"", define->ns);
7210 fprintf(output, ">%s</name>\n", define->name);
7211 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007212 xmlRelaxNGDumpDefines(output, define->attrs);
7213 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007214 fprintf(output, "</element>\n");
7215 break;
7216 case XML_RELAXNG_LIST:
7217 fprintf(output, "<list>\n");
7218 xmlRelaxNGDumpDefines(output, define->content);
7219 fprintf(output, "</list>\n");
7220 break;
7221 case XML_RELAXNG_ONEORMORE:
7222 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007223 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007224 fprintf(output, "</oneOrMore>\n");
7225 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007226 case XML_RELAXNG_ZEROORMORE:
7227 fprintf(output, "<zeroOrMore>\n");
7228 xmlRelaxNGDumpDefines(output, define->content);
7229 fprintf(output, "</zeroOrMore>\n");
7230 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007231 case XML_RELAXNG_CHOICE:
7232 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007233 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007234 fprintf(output, "</choice>\n");
7235 break;
7236 case XML_RELAXNG_GROUP:
7237 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007238 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007239 fprintf(output, "</group>\n");
7240 break;
7241 case XML_RELAXNG_INTERLEAVE:
7242 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007243 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007244 fprintf(output, "</interleave>\n");
7245 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007246 case XML_RELAXNG_OPTIONAL:
7247 fprintf(output, "<optional>\n");
7248 xmlRelaxNGDumpDefines(output, define->content);
7249 fprintf(output, "</optional>\n");
7250 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007251 case XML_RELAXNG_ATTRIBUTE:
7252 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007253 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007254 fprintf(output, "</attribute>\n");
7255 break;
7256 case XML_RELAXNG_DEF:
7257 fprintf(output, "<define");
7258 if (define->name != NULL)
7259 fprintf(output, " name=\"%s\"", define->name);
7260 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007261 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007262 fprintf(output, "</define>\n");
7263 break;
7264 case XML_RELAXNG_REF:
7265 fprintf(output, "<ref");
7266 if (define->name != NULL)
7267 fprintf(output, " name=\"%s\"", define->name);
7268 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007269 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007270 fprintf(output, "</ref>\n");
7271 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007272 case XML_RELAXNG_PARENTREF:
7273 fprintf(output, "<parentRef");
7274 if (define->name != NULL)
7275 fprintf(output, " name=\"%s\"", define->name);
7276 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007277 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00007278 fprintf(output, "</parentRef>\n");
7279 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007280 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00007281 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007282 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00007283 fprintf(output, "</externalRef>\n");
7284 break;
7285 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007286 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007287 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00007288 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007289 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007290 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007291 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007292 TODO
7293 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007294 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007295 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00007296 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007297 }
7298}
7299
7300/**
7301 * xmlRelaxNGDumpGrammar:
7302 * @output: the file output
7303 * @grammar: a grammar structure
7304 * @top: is this a top grammar
7305 *
7306 * Dump a RelaxNG structure back
7307 */
7308static void
7309xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7310{
7311 if (grammar == NULL)
7312 return;
7313
7314 fprintf(output, "<grammar");
7315 if (top)
7316 fprintf(output,
7317 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7318 switch(grammar->combine) {
7319 case XML_RELAXNG_COMBINE_UNDEFINED:
7320 break;
7321 case XML_RELAXNG_COMBINE_CHOICE:
7322 fprintf(output, " combine=\"choice\"");
7323 break;
7324 case XML_RELAXNG_COMBINE_INTERLEAVE:
7325 fprintf(output, " combine=\"interleave\"");
7326 break;
7327 default:
7328 fprintf(output, " <!-- invalid combine value -->");
7329 }
7330 fprintf(output, ">\n");
7331 if (grammar->start == NULL) {
7332 fprintf(output, " <!-- grammar had no start -->");
7333 } else {
7334 fprintf(output, "<start>\n");
7335 xmlRelaxNGDumpDefine(output, grammar->start);
7336 fprintf(output, "</start>\n");
7337 }
7338 /* TODO ? Dump the defines ? */
7339 fprintf(output, "</grammar>\n");
7340}
7341
7342/**
7343 * xmlRelaxNGDump:
7344 * @output: the file output
7345 * @schema: a schema structure
7346 *
7347 * Dump a RelaxNG structure back
7348 */
7349void
7350xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7351{
7352 if (schema == NULL) {
7353 fprintf(output, "RelaxNG empty or failed to compile\n");
7354 return;
7355 }
7356 fprintf(output, "RelaxNG: ");
7357 if (schema->doc == NULL) {
7358 fprintf(output, "no document\n");
7359 } else if (schema->doc->URL != NULL) {
7360 fprintf(output, "%s\n", schema->doc->URL);
7361 } else {
7362 fprintf(output, "\n");
7363 }
7364 if (schema->topgrammar == NULL) {
7365 fprintf(output, "RelaxNG has no top grammar\n");
7366 return;
7367 }
7368 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7369}
7370
Daniel Veillardfebcca42003-02-16 15:44:18 +00007371/**
7372 * xmlRelaxNGDumpTree:
7373 * @output: the file output
7374 * @schema: a schema structure
7375 *
7376 * Dump the transformed RelaxNG tree.
7377 */
7378void
7379xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7380{
7381 if (schema == NULL) {
7382 fprintf(output, "RelaxNG empty or failed to compile\n");
7383 return;
7384 }
7385 if (schema->doc == NULL) {
7386 fprintf(output, "no document\n");
7387 } else {
7388 xmlDocDump(output, schema->doc);
7389 }
7390}
7391
Daniel Veillard6eadf632003-01-23 18:29:16 +00007392/************************************************************************
7393 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007394 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007395 * *
7396 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007397static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7398 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007399
7400/**
7401 * xmlRelaxNGValidateCompiledCallback:
7402 * @exec: the regular expression instance
7403 * @token: the token which matched
7404 * @transdata: callback data, the define for the subelement if available
7405 @ @inputdata: callback data, the Relax NG validation context
7406 *
7407 * Handle the callback and if needed validate the element children.
7408 */
7409static void
7410xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7411 const xmlChar *token,
7412 void *transdata,
7413 void *inputdata) {
7414 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7415 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7416 int ret;
7417
7418#ifdef DEBUG_COMPILE
7419 xmlGenericError(xmlGenericErrorContext,
7420 "Compiled callback for: '%s'\n", token);
7421#endif
7422 if (ctxt == NULL) {
7423 fprintf(stderr, "callback on %s missing context\n", token);
7424 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7425 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7426 return;
7427 }
7428 if (define == NULL) {
7429 if (token[0] == '#')
7430 return;
7431 fprintf(stderr, "callback on %s missing define\n", token);
7432 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7433 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7434 return;
7435 }
7436 if ((ctxt == NULL) || (define == NULL)) {
7437 fprintf(stderr, "callback on %s missing info\n", token);
7438 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7439 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7440 return;
7441 } else if (define->type != XML_RELAXNG_ELEMENT) {
7442 fprintf(stderr, "callback on %s define is not element\n", token);
7443 if (ctxt->errNo == XML_RELAXNG_OK)
7444 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7445 return;
7446 }
7447 ret = xmlRelaxNGValidateDefinition(ctxt, define);
7448}
7449
7450/**
7451 * xmlRelaxNGValidateCompiledContent:
7452 * @ctxt: the RelaxNG validation context
7453 * @regexp: the regular expression as compiled
7454 * @content: list of children to test against the regexp
7455 *
7456 * Validate the content model of an element or start using the regexp
7457 *
7458 * Returns 0 in case of success, -1 in case of error.
7459 */
7460static int
7461xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7462 xmlRegexpPtr regexp, xmlNodePtr content) {
7463 xmlRegExecCtxtPtr exec;
7464 xmlNodePtr cur;
7465 int ret;
7466
7467 if ((ctxt == NULL) || (regexp == NULL))
7468 return(-1);
7469 exec = xmlRegNewExecCtxt(regexp,
7470 xmlRelaxNGValidateCompiledCallback, ctxt);
7471 cur = content;
7472 while (cur != NULL) {
7473 ctxt->state->seq = cur;
7474 switch (cur->type) {
7475 case XML_TEXT_NODE:
7476 case XML_CDATA_SECTION_NODE:
7477 if (xmlIsBlankNode(cur))
7478 break;
7479 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7480 if (ret < 0) {
7481 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7482 }
7483 break;
7484 case XML_ELEMENT_NODE:
7485 if (cur->ns != NULL) {
7486 ret = xmlRegExecPushString2(exec, cur->name,
7487 cur->ns->href, ctxt);
7488 } else {
7489 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7490 }
7491 if (ret < 0) {
7492 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7493 }
7494 break;
7495 default:
7496 break;
7497 }
7498 if (ret < 0) break;
7499 /*
7500 * Switch to next element
7501 */
7502 cur = cur->next;
7503 }
7504 ret = xmlRegExecPushString(exec, NULL, NULL);
7505 if (ret == 1) {
7506 ret = 0;
7507 ctxt->state->seq = NULL;
7508 } else if (ret == 0) {
7509 /*
Daniel Veillardf4e55762003-04-15 23:32:22 +00007510 * TODO: get some of the names needed to exit the current state of exec
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007511 */
7512 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7513 ret = -1;
7514 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7515 xmlRelaxNGDumpValidError(ctxt);
7516 } else {
7517 ret = -1;
7518 }
7519 xmlRegFreeExecCtxt(exec);
7520 return(ret);
7521}
7522
7523/************************************************************************
7524 * *
7525 * Progressive validation of when possible *
7526 * *
7527 ************************************************************************/
Daniel Veillardf4e55762003-04-15 23:32:22 +00007528static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7529 xmlRelaxNGDefinePtr defines);
7530static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt);
7531
7532/**
7533 * xmlRelaxNGElemPush:
7534 * @ctxt: the validation context
7535 * @exec: the regexp runtime for the new content model
7536 *
7537 * Push a new regexp for the current node content model on the stack
7538 *
7539 * Returns 0 in case of success and -1 in case of error.
7540 */
7541static int
7542xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) {
7543 if (ctxt->elemTab == NULL) {
7544 ctxt->elemMax = 10;
7545 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7546 sizeof(xmlRegExecCtxtPtr));
7547 if (ctxt->elemTab == NULL) {
7548 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7549 return(-1);
7550 }
7551 }
7552 if (ctxt->elemNr >= ctxt->elemMax) {
7553 ctxt->elemMax *= 2;
7554 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7555 ctxt->elemMax * sizeof(xmlRegExecCtxtPtr));
7556 if (ctxt->elemTab == NULL) {
7557 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7558 return(-1);
7559 }
7560 }
7561 ctxt->elemTab[ctxt->elemNr++] = exec;
7562 ctxt->elem = exec;
7563 return(0);
7564}
7565
7566/**
7567 * xmlRelaxNGElemPop:
7568 * @ctxt: the validation context
7569 *
7570 * Pop the regexp of the current node content model from the stack
7571 *
7572 * Returns the exec or NULL if empty
7573 */
7574static xmlRegExecCtxtPtr
7575xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) {
7576 xmlRegExecCtxtPtr ret;
7577
7578 if (ctxt->elemNr <= 0) return(NULL);
7579 ctxt->elemNr--;
7580 ret = ctxt->elemTab[ctxt->elemNr];
7581 ctxt->elemTab[ctxt->elemNr] = NULL;
7582 if (ctxt->elemNr > 0)
7583 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7584 else
7585 ctxt->elem = NULL;
7586 return(ret);
7587}
7588
7589/**
7590 * xmlRelaxNGValidateProgressiveCallback:
7591 * @exec: the regular expression instance
7592 * @token: the token which matched
7593 * @transdata: callback data, the define for the subelement if available
7594 @ @inputdata: callback data, the Relax NG validation context
7595 *
7596 * Handle the callback and if needed validate the element children.
7597 * some of the in/out informations are passed via the context in @inputdata.
7598 */
7599static void
7600xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7601 const xmlChar *token,
7602 void *transdata,
7603 void *inputdata) {
7604 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7605 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7606 xmlRelaxNGValidStatePtr state;
7607 xmlNodePtr node = ctxt->pnode;
7608 int ret;
7609
7610#ifdef DEBUG_PROGRESSIVE
7611 xmlGenericError(xmlGenericErrorContext,
7612 "Progressive callback for: '%s'\n", token);
7613#endif
7614 if (ctxt == NULL) {
7615 fprintf(stderr, "callback on %s missing context\n", token);
7616 return;
7617 }
7618 ctxt->pstate = 1;
7619 if (define == NULL) {
7620 if (token[0] == '#')
7621 return;
7622 fprintf(stderr, "callback on %s missing define\n", token);
7623 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7624 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7625 ctxt->pstate = -1;
7626 return;
7627 }
7628 if ((ctxt == NULL) || (define == NULL)) {
7629 fprintf(stderr, "callback on %s missing info\n", token);
7630 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7631 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7632 ctxt->pstate = -1;
7633 return;
7634 } else if (define->type != XML_RELAXNG_ELEMENT) {
7635 fprintf(stderr, "callback on %s define is not element\n", token);
7636 if (ctxt->errNo == XML_RELAXNG_OK)
7637 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7638 ctxt->pstate = -1;
7639 return;
7640 }
7641 if (node->type != XML_ELEMENT_NODE) {
7642 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7643 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7644 xmlRelaxNGDumpValidError(ctxt);
7645 ctxt->pstate = -1;
7646 return;
7647 }
7648 if (define->contModel == NULL) {
7649 /*
7650 * this node cannot be validated in a streamable fashion
7651 */
7652#ifdef DEBUG_PROGRESSIVE
7653 xmlGenericError(xmlGenericErrorContext,
7654 "Element '%s' validation is not streamable\n", token);
7655#endif
7656 ctxt->pstate = 0;
7657 ctxt->pdef = define;
7658 return;
7659 }
7660 exec = xmlRegNewExecCtxt(define->contModel,
7661 xmlRelaxNGValidateProgressiveCallback,
7662 ctxt);
7663 if (exec == NULL) {
7664 ctxt->pstate = -1;
7665 return;
7666 }
7667 xmlRelaxNGElemPush(ctxt, exec);
7668
7669 /*
7670 * Validate the attributes part of the content.
7671 */
7672 state = xmlRelaxNGNewValidState(ctxt, node);
7673 if (state == NULL) {
7674 ctxt->pstate = -1;
7675 return;
7676 }
7677 ctxt->state = state;
7678 if (define->attrs != NULL) {
7679 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7680 if (ret != 0) {
7681 ctxt->pstate = -1;
7682 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7683 }
7684 }
7685 ctxt->state->seq = NULL;
7686 ret = xmlRelaxNGValidateElementEnd(ctxt);
7687 if (ret != 0) {
7688 ctxt->pstate = -1;
7689 }
7690 xmlRelaxNGFreeValidState(ctxt, state);
7691 ctxt->state = NULL;
7692}
7693
7694/**
7695 * xmlRelaxNGValidatePushElement:
7696 * @ctxt: the validation context
7697 * @doc: a document instance
7698 * @elem: an element instance
7699 *
7700 * Push a new element start on the RelaxNG validation stack.
7701 *
7702 * returns 1 if no validation problem was found or 0 if validating the
7703 * element requires a full node, and -1 in case of error.
7704 */
7705int
7706xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc,
7707 xmlNodePtr elem)
7708{
7709 int ret = 1;
7710
7711 if ((ctxt == NULL) || (elem == NULL))
7712 return (-1);
7713
7714#ifdef DEBUG_PROGRESSIVE
7715 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
7716#endif
7717 if (ctxt->elem == 0) {
7718 xmlRelaxNGPtr schema;
7719 xmlRelaxNGGrammarPtr grammar;
7720 xmlRegExecCtxtPtr exec;
7721 xmlRelaxNGDefinePtr define;
7722
7723 schema = ctxt->schema;
7724 if (schema == NULL) {
7725 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7726 return (-1);
7727 }
7728 grammar = schema->topgrammar;
7729 if ((grammar == NULL) || (grammar->start == NULL)) {
7730 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7731 return (-1);
7732 }
7733 define = grammar->start;
7734 if (define->contModel == NULL) {
7735 ctxt->pdef = define;
7736 return (0);
7737 }
7738 exec = xmlRegNewExecCtxt(define->contModel,
7739 xmlRelaxNGValidateProgressiveCallback,
7740 ctxt);
7741 if (exec == NULL) {
7742 return (-1);
7743 }
7744 xmlRelaxNGElemPush(ctxt, exec);
7745 }
7746 ctxt->pnode = elem;
7747 ctxt->pstate = 0;
7748 if (elem->ns != NULL) {
7749 ret =
7750 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
7751 ctxt);
7752 } else {
7753 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
7754 }
7755 if (ret < 0) {
7756 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
7757 } else {
7758 if (ctxt->pstate == 0)
7759 ret = 0;
7760 else if (ctxt->pstate < 0)
7761 ret = -1;
7762 else
7763 ret = 1;
7764 }
7765#ifdef DEBUG_PROGRESSIVE
7766 if (ret < 0)
7767 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
7768 elem->name);
7769#endif
7770 return (ret);
7771}
7772
7773/**
7774 * xmlRelaxNGValidatePushCData:
7775 * @ctxt: the RelaxNG validation context
7776 * @data: some character data read
7777 * @len: the lenght of the data
7778 *
7779 * check the CData parsed for validation in the current stack
7780 *
7781 * returns 1 if no validation problem was found or -1 otherwise
7782 */
7783int
7784xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
7785 const xmlChar * data, int len)
7786{
7787 int ret = 1;
7788
7789 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
7790 return (-1);
7791
7792#ifdef DEBUG_PROGRESSIVE
7793 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
7794#endif
7795
7796 while (*data != 0) {
7797 if (!IS_BLANK(*data))
7798 break;
7799 data++;
7800 }
7801 if (*data == 0)
7802 return(1);
7803
7804 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
7805 if (ret < 0) {
7806 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, " TODO ");
7807#ifdef DEBUG_PROGRESSIVE
7808 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
7809#endif
7810
7811 return(-1);
7812 }
7813 return(1);
7814}
7815
7816/**
7817 * xmlRelaxNGValidatePopElement:
7818 * @ctxt: the RelaxNG validation context
7819 * @doc: a document instance
7820 * @elem: an element instance
7821 *
7822 * Pop the element end from the RelaxNG validation stack.
7823 *
7824 * returns 1 if no validation problem was found or 0 otherwise
7825 */
7826int
7827xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
7828 xmlDocPtr doc ATTRIBUTE_UNUSED,
7829 xmlNodePtr elem) {
7830 int ret;
7831 xmlRegExecCtxtPtr exec;
7832
7833 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) return(-1);
7834#ifdef DEBUG_PROGRESSIVE
7835 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
7836#endif
7837 /*
7838 * verify that we reached a terminal state of the content model.
7839 */
7840 exec = xmlRelaxNGElemPop(ctxt);
7841 ret = xmlRegExecPushString(exec, NULL, NULL);
7842 if (ret == 0) {
7843 /*
7844 * TODO: get some of the names needed to exit the current state of exec
7845 */
7846 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7847 ret = -1;
7848 } else if (ret < 0) {
7849 ret = -1;
7850 } else {
7851 ret = 1;
7852 }
7853 xmlRegFreeExecCtxt(exec);
7854#ifdef DEBUG_PROGRESSIVE
7855 if (ret < 0)
7856 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
7857 elem->name);
7858#endif
7859 return(ret);
7860}
7861
7862/**
7863 * xmlRelaxNGValidateFullElement:
7864 * @ctxt: the validation context
7865 * @doc: a document instance
7866 * @elem: an element instance
7867 *
7868 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
7869 * 0 and the content of the node has been expanded.
7870 *
7871 * returns 1 if no validation problem was found or -1 in case of error.
7872 */
7873int
7874xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc,
7875 xmlNodePtr elem) {
7876 int ret;
7877 xmlRelaxNGValidStatePtr state;
7878
7879 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) return(-1);
7880#ifdef DEBUG_PROGRESSIVE
7881 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
7882#endif
7883 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
7884 if (state == NULL) {
7885 return(-1);
7886 }
7887 state->seq = elem;
7888 ctxt->state = state;
7889 ctxt->errNo = XML_RELAXNG_OK;
7890 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
7891 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) ret = -1;
7892 else ret = 1;
7893 xmlRelaxNGFreeValidState(ctxt, state);
7894 ctxt->state = NULL;
7895#ifdef DEBUG_PROGRESSIVE
7896 if (ret < 0)
7897 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
7898 elem->name);
7899#endif
7900 return(ret);
7901}
7902
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007903/************************************************************************
7904 * *
7905 * Generic interpreted validation implementation *
7906 * *
7907 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007908static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7909 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007910
7911/**
7912 * xmlRelaxNGSkipIgnored:
7913 * @ctxt: a schema validation context
7914 * @node: the top node.
7915 *
7916 * Skip ignorable nodes in that context
7917 *
7918 * Returns the new sibling or NULL in case of error.
7919 */
7920static xmlNodePtr
7921xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7922 xmlNodePtr node) {
7923 /*
7924 * TODO complete and handle entities
7925 */
7926 while ((node != NULL) &&
7927 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007928 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007929 (((node->type == XML_TEXT_NODE) ||
7930 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007931 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
7932 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007933 node = node->next;
7934 }
7935 return(node);
7936}
7937
7938/**
Daniel Veillardedc91922003-01-26 00:52:04 +00007939 * xmlRelaxNGNormalize:
7940 * @ctxt: a schema validation context
7941 * @str: the string to normalize
7942 *
7943 * Implements the normalizeWhiteSpace( s ) function from
7944 * section 6.2.9 of the spec
7945 *
7946 * Returns the new string or NULL in case of error.
7947 */
7948static xmlChar *
7949xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
7950 xmlChar *ret, *p;
7951 const xmlChar *tmp;
7952 int len;
7953
7954 if (str == NULL)
7955 return(NULL);
7956 tmp = str;
7957 while (*tmp != 0) tmp++;
7958 len = tmp - str;
7959
7960 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7961 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007962 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007963 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007964 } else {
7965 xmlGenericError(xmlGenericErrorContext,
7966 "xmlRelaxNGNormalize: out of memory\n");
7967 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007968 return(NULL);
7969 }
7970 p = ret;
7971 while (IS_BLANK(*str)) str++;
7972 while (*str != 0) {
7973 if (IS_BLANK(*str)) {
7974 while (IS_BLANK(*str)) str++;
7975 if (*str == 0)
7976 break;
7977 *p++ = ' ';
7978 } else
7979 *p++ = *str++;
7980 }
7981 *p = 0;
7982 return(ret);
7983}
7984
7985/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007986 * xmlRelaxNGValidateDatatype:
7987 * @ctxt: a Relax-NG validation context
7988 * @value: the string value
7989 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007990 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007991 *
7992 * Validate the given value against the dataype
7993 *
7994 * Returns 0 if the validation succeeded or an error code.
7995 */
7996static int
7997xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007998 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007999 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008000 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008001 void *result = NULL;
8002 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008003
8004 if ((define == NULL) || (define->data == NULL)) {
8005 return(-1);
8006 }
8007 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008008 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008009 if ((define->attrs != NULL) &&
8010 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008011 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008012 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008013 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008014 }
8015 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008016 ret = -1;
8017 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008018 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008019 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8020 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008021 return(-1);
8022 } else if (ret == 1) {
8023 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008024 } else if (ret == 2) {
8025 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008026 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008027 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008028 ret = -1;
8029 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008030 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008031 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8032 if (lib->facet != NULL) {
8033 tmp = lib->facet(lib->data, define->name, cur->name,
8034 cur->value, value, result);
8035 if (tmp != 0)
8036 ret = -1;
8037 }
8038 cur = cur->next;
8039 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008040 if ((ret == 0) && (define->content != NULL)) {
8041 const xmlChar *oldvalue, *oldendvalue;
8042
8043 oldvalue = ctxt->state->value;
8044 oldendvalue = ctxt->state->endvalue;
8045 ctxt->state->value = (xmlChar *) value;
8046 ctxt->state->endvalue = NULL;
8047 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8048 ctxt->state->value = (xmlChar *) oldvalue;
8049 ctxt->state->endvalue = (xmlChar *) oldendvalue;
8050 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008051 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8052 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008053 return(ret);
8054}
8055
8056/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008057 * xmlRelaxNGNextValue:
8058 * @ctxt: a Relax-NG validation context
8059 *
8060 * Skip to the next value when validating within a list
8061 *
8062 * Returns 0 if the operation succeeded or an error code.
8063 */
8064static int
8065xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
8066 xmlChar *cur;
8067
8068 cur = ctxt->state->value;
8069 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8070 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00008071 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008072 return(0);
8073 }
8074 while (*cur != 0) cur++;
8075 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
8076 if (cur == ctxt->state->endvalue)
8077 ctxt->state->value = NULL;
8078 else
8079 ctxt->state->value = cur;
8080 return(0);
8081}
8082
8083/**
8084 * xmlRelaxNGValidateValueList:
8085 * @ctxt: a Relax-NG validation context
8086 * @defines: the list of definitions to verify
8087 *
8088 * Validate the given set of definitions for the current value
8089 *
8090 * Returns 0 if the validation succeeded or an error code.
8091 */
8092static int
8093xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8094 xmlRelaxNGDefinePtr defines) {
8095 int ret = 0;
8096
8097 while (defines != NULL) {
8098 ret = xmlRelaxNGValidateValue(ctxt, defines);
8099 if (ret != 0)
8100 break;
8101 defines = defines->next;
8102 }
8103 return(ret);
8104}
8105
8106/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008107 * xmlRelaxNGValidateValue:
8108 * @ctxt: a Relax-NG validation context
8109 * @define: the definition to verify
8110 *
8111 * Validate the given definition for the current value
8112 *
8113 * Returns 0 if the validation succeeded or an error code.
8114 */
8115static int
8116xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8117 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00008118 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008119 xmlChar *value;
8120
8121 value = ctxt->state->value;
8122 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008123 case XML_RELAXNG_EMPTY: {
8124 if ((value != NULL) && (value[0] != 0)) {
8125 int idx = 0;
8126
8127 while (IS_BLANK(value[idx]))
8128 idx++;
8129 if (value[idx] != 0)
8130 ret = -1;
8131 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008132 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00008133 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008134 case XML_RELAXNG_TEXT:
8135 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00008136 case XML_RELAXNG_VALUE: {
8137 if (!xmlStrEqual(value, define->value)) {
8138 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008139 xmlRelaxNGTypeLibraryPtr lib;
8140
8141 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00008142 if ((lib != NULL) && (lib->comp != NULL)) {
8143 ret = lib->comp(lib->data, define->name,
8144 define->value, define->node,
8145 (void *) define->attrs,
8146 value, ctxt->state->node);
8147 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00008148 ret = -1;
8149 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008150 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008151 return(-1);
8152 } else if (ret == 1) {
8153 ret = 0;
8154 } else {
8155 ret = -1;
8156 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008157 } else {
8158 xmlChar *nval, *nvalue;
8159
8160 /*
8161 * TODO: trivial optimizations are possible by
8162 * computing at compile-time
8163 */
8164 nval = xmlRelaxNGNormalize(ctxt, define->value);
8165 nvalue = xmlRelaxNGNormalize(ctxt, value);
8166
Daniel Veillardea3f3982003-01-26 19:45:18 +00008167 if ((nval == NULL) || (nvalue == NULL) ||
8168 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00008169 ret = -1;
8170 if (nval != NULL)
8171 xmlFree(nval);
8172 if (nvalue != NULL)
8173 xmlFree(nvalue);
8174 }
8175 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008176 if (ret == 0)
8177 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00008178 break;
8179 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008180 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008181 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8182 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008183 if (ret == 0)
8184 xmlRelaxNGNextValue(ctxt);
8185
8186 break;
8187 }
8188 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008189 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008190 xmlChar *oldvalue;
8191
8192 oldflags = ctxt->flags;
8193 ctxt->flags |= FLAGS_IGNORABLE;
8194
8195 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008196 while (list != NULL) {
8197 ret = xmlRelaxNGValidateValue(ctxt, list);
8198 if (ret == 0) {
8199 break;
8200 }
8201 ctxt->state->value = oldvalue;
8202 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008203 }
8204 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008205 if (ret != 0) {
8206 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8207 xmlRelaxNGDumpValidError(ctxt);
8208 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008209 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008210 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008211 if (ret == 0)
8212 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008213 break;
8214 }
8215 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008216 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008217 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00008218#ifdef DEBUG_LIST
8219 int nb_values = 0;
8220#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008221
8222 oldvalue = ctxt->state->value;
8223 oldend = ctxt->state->endvalue;
8224
8225 val = xmlStrdup(oldvalue);
8226 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008227 val = xmlStrdup(BAD_CAST "");
8228 }
8229 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008230 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008231 return(-1);
8232 }
8233 cur = val;
8234 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00008235 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008236 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008237 cur++;
8238#ifdef DEBUG_LIST
8239 nb_values++;
8240#endif
8241 while (IS_BLANK(*cur))
8242 *cur++ = 0;
8243 } else
8244 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008245 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008246#ifdef DEBUG_LIST
8247 xmlGenericError(xmlGenericErrorContext,
8248 "list value: '%s' found %d items\n", oldvalue, nb_values);
8249 nb_values = 0;
8250#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008251 ctxt->state->endvalue = cur;
8252 cur = val;
8253 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008254
Daniel Veillardfd573f12003-03-16 17:52:32 +00008255 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008256
Daniel Veillardfd573f12003-03-16 17:52:32 +00008257 while (list != NULL) {
8258 if (ctxt->state->value == ctxt->state->endvalue)
8259 ctxt->state->value = NULL;
8260 ret = xmlRelaxNGValidateValue(ctxt, list);
8261 if (ret != 0) {
8262#ifdef DEBUG_LIST
8263 xmlGenericError(xmlGenericErrorContext,
8264 "Failed to validate value: '%s' with %d rule\n",
8265 ctxt->state->value, nb_values);
8266#endif
8267 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008268 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008269#ifdef DEBUG_LIST
8270 nb_values++;
8271#endif
8272 list = list->next;
8273 }
8274
8275 if ((ret == 0) && (ctxt->state->value != NULL) &&
8276 (ctxt->state->value != ctxt->state->endvalue)) {
8277 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
8278 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008279 }
8280 xmlFree(val);
8281 ctxt->state->value = oldvalue;
8282 ctxt->state->endvalue = oldend;
8283 break;
8284 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008285 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008286 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8287 if (ret != 0) {
8288 break;
8289 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008290 /* no break on purpose */
8291 case XML_RELAXNG_ZEROORMORE: {
8292 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008293
8294 oldflags = ctxt->flags;
8295 ctxt->flags |= FLAGS_IGNORABLE;
8296 cur = ctxt->state->value;
8297 temp = NULL;
8298 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8299 (temp != cur)) {
8300 temp = cur;
8301 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8302 if (ret != 0) {
8303 ctxt->state->value = temp;
8304 ret = 0;
8305 break;
8306 }
8307 cur = ctxt->state->value;
8308 }
8309 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008310 if (ret != 0) {
8311 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8312 xmlRelaxNGDumpValidError(ctxt);
8313 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008314 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008315 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008316 break;
8317 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008318 case XML_RELAXNG_EXCEPT: {
8319 xmlRelaxNGDefinePtr list;
8320
8321 list = define->content;
8322 while (list != NULL) {
8323 ret = xmlRelaxNGValidateValue(ctxt, list);
8324 if (ret == 0) {
8325 ret = -1;
8326 break;
8327 } else
8328 ret = 0;
8329 list = list->next;
8330 }
8331 break;
8332 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008333 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008334 case XML_RELAXNG_GROUP: {
8335 xmlRelaxNGDefinePtr list;
8336
8337 list = define->content;
8338 while (list != NULL) {
8339 ret = xmlRelaxNGValidateValue(ctxt, list);
8340 if (ret != 0) {
8341 ret = -1;
8342 break;
8343 } else
8344 ret = 0;
8345 list = list->next;
8346 }
Daniel Veillardd4310742003-02-18 21:12:46 +00008347 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008348 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008349 case XML_RELAXNG_REF:
8350 case XML_RELAXNG_PARENTREF:
8351 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8352 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008353 default:
8354 TODO
8355 ret = -1;
8356 }
8357 return(ret);
8358}
8359
8360/**
8361 * xmlRelaxNGValidateValueContent:
8362 * @ctxt: a Relax-NG validation context
8363 * @defines: the list of definitions to verify
8364 *
8365 * Validate the given definitions for the current value
8366 *
8367 * Returns 0 if the validation succeeded or an error code.
8368 */
8369static int
8370xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8371 xmlRelaxNGDefinePtr defines) {
8372 int ret = 0;
8373
8374 while (defines != NULL) {
8375 ret = xmlRelaxNGValidateValue(ctxt, defines);
8376 if (ret != 0)
8377 break;
8378 defines = defines->next;
8379 }
8380 return(ret);
8381}
8382
8383/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008384 * xmlRelaxNGAttributeMatch:
8385 * @ctxt: a Relax-NG validation context
8386 * @define: the definition to check
8387 * @prop: the attribute
8388 *
8389 * Check if the attribute matches the definition nameClass
8390 *
8391 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8392 */
8393static int
8394xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8395 xmlRelaxNGDefinePtr define,
8396 xmlAttrPtr prop) {
8397 int ret;
8398
8399 if (define->name != NULL) {
8400 if (!xmlStrEqual(define->name, prop->name))
8401 return(0);
8402 }
8403 if (define->ns != NULL) {
8404 if (define->ns[0] == 0) {
8405 if (prop->ns != NULL)
8406 return(0);
8407 } else {
8408 if ((prop->ns == NULL) ||
8409 (!xmlStrEqual(define->ns, prop->ns->href)))
8410 return(0);
8411 }
8412 }
8413 if (define->nameClass == NULL)
8414 return(1);
8415 define = define->nameClass;
8416 if (define->type == XML_RELAXNG_EXCEPT) {
8417 xmlRelaxNGDefinePtr list;
8418
8419 list = define->content;
8420 while (list != NULL) {
8421 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8422 if (ret == 1)
8423 return(0);
8424 if (ret < 0)
8425 return(ret);
8426 list = list->next;
8427 }
8428 } else {
8429 TODO
8430 }
8431 return(1);
8432}
8433
8434/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008435 * xmlRelaxNGValidateAttribute:
8436 * @ctxt: a Relax-NG validation context
8437 * @define: the definition to verify
8438 *
8439 * Validate the given attribute definition for that node
8440 *
8441 * Returns 0 if the validation succeeded or an error code.
8442 */
8443static int
8444xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8445 xmlRelaxNGDefinePtr define) {
8446 int ret = 0, i;
8447 xmlChar *value, *oldvalue;
8448 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008449 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008450
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008451 if (ctxt->state->nbAttrLeft <= 0)
8452 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008453 if (define->name != NULL) {
8454 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8455 tmp = ctxt->state->attrs[i];
8456 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8457 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8458 (tmp->ns == NULL)) ||
8459 ((tmp->ns != NULL) &&
8460 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8461 prop = tmp;
8462 break;
8463 }
8464 }
8465 }
8466 if (prop != NULL) {
8467 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8468 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008469 oldseq = ctxt->state->seq;
8470 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008471 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00008472 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008473 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008474 if (ctxt->state->value != NULL)
8475 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008476 if (value != NULL)
8477 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008478 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008479 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008480 if (ret == 0) {
8481 /*
8482 * flag the attribute as processed
8483 */
8484 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008485 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008486 }
8487 } else {
8488 ret = -1;
8489 }
8490#ifdef DEBUG
8491 xmlGenericError(xmlGenericErrorContext,
8492 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8493#endif
8494 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008495 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8496 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00008497 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00008498 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008499 prop = tmp;
8500 break;
8501 }
8502 }
8503 if (prop != NULL) {
8504 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8505 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008506 oldseq = ctxt->state->seq;
8507 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008508 ctxt->state->value = value;
8509 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008510 if (ctxt->state->value != NULL)
8511 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008512 if (value != NULL)
8513 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008514 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008515 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008516 if (ret == 0) {
8517 /*
8518 * flag the attribute as processed
8519 */
8520 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008521 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008522 }
8523 } else {
8524 ret = -1;
8525 }
8526#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00008527 if (define->ns != NULL) {
8528 xmlGenericError(xmlGenericErrorContext,
8529 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8530 define->ns, ret);
8531 } else {
8532 xmlGenericError(xmlGenericErrorContext,
8533 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8534 ret);
8535 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008536#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008537 }
8538
8539 return(ret);
8540}
8541
8542/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008543 * xmlRelaxNGValidateAttributeList:
8544 * @ctxt: a Relax-NG validation context
8545 * @define: the list of definition to verify
8546 *
8547 * Validate the given node against the list of attribute definitions
8548 *
8549 * Returns 0 if the validation succeeded or an error code.
8550 */
8551static int
8552xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8553 xmlRelaxNGDefinePtr defines) {
8554 int ret = 0;
8555 while (defines != NULL) {
8556 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
8557 ret = -1;
8558 defines = defines->next;
8559 }
8560 return(ret);
8561}
8562
8563/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008564 * xmlRelaxNGNodeMatchesList:
8565 * @node: the node
8566 * @list: a NULL terminated array of definitions
8567 *
8568 * Check if a node can be matched by one of the definitions
8569 *
8570 * Returns 1 if matches 0 otherwise
8571 */
8572static int
8573xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8574 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008575 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008576
8577 if ((node == NULL) || (list == NULL))
8578 return(0);
8579
8580 cur = list[i++];
8581 while (cur != NULL) {
8582 if ((node->type == XML_ELEMENT_NODE) &&
8583 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008584 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8585 if (tmp == 1)
8586 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008587 } else if (((node->type == XML_TEXT_NODE) ||
8588 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008589 (cur->type == XML_RELAXNG_TEXT)) {
8590 return(1);
8591 }
8592 cur = list[i++];
8593 }
8594 return(0);
8595}
8596
8597/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008598 * xmlRelaxNGValidateInterleave:
8599 * @ctxt: a Relax-NG validation context
8600 * @define: the definition to verify
8601 *
8602 * Validate an interleave definition for a node.
8603 *
8604 * Returns 0 if the validation succeeded or an error code.
8605 */
8606static int
8607xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
8608 xmlRelaxNGDefinePtr define) {
8609 int ret = 0, i, nbgroups, left;
8610 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008611 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008612
8613 xmlRelaxNGValidStatePtr oldstate;
8614 xmlRelaxNGPartitionPtr partitions;
8615 xmlRelaxNGInterleaveGroupPtr group = NULL;
8616 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8617 xmlNodePtr *list = NULL, *lasts = NULL;
8618
8619 if (define->data != NULL) {
8620 partitions = (xmlRelaxNGPartitionPtr) define->data;
8621 nbgroups = partitions->nbgroups;
8622 left = nbgroups;
8623 } else {
8624 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8625 return(-1);
8626 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008627 /*
8628 * Optimizations for MIXED
8629 */
8630 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00008631 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008632 ctxt->flags |= FLAGS_MIXED_CONTENT;
8633 if (nbgroups == 2) {
8634 /*
8635 * this is a pure <mixed> case
8636 */
8637 if (ctxt->state != NULL)
8638 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8639 ctxt->state->seq);
8640 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8641 ret = xmlRelaxNGValidateDefinition(ctxt,
8642 partitions->groups[1]->rule);
8643 else
8644 ret = xmlRelaxNGValidateDefinition(ctxt,
8645 partitions->groups[0]->rule);
8646 if (ret == 0) {
8647 if (ctxt->state != NULL)
8648 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8649 ctxt->state->seq);
8650 }
8651 ctxt->flags = oldflags;
8652 return(ret);
8653 }
8654 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008655
8656 /*
8657 * Build arrays to store the first and last node of the chain
8658 * pertaining to each group
8659 */
8660 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8661 if (list == NULL) {
8662 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8663 return(-1);
8664 }
8665 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8666 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8667 if (lasts == NULL) {
8668 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8669 return(-1);
8670 }
8671 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8672
8673 /*
8674 * Walk the sequence of children finding the right group and
8675 * sorting them in sequences.
8676 */
8677 cur = ctxt->state->seq;
8678 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8679 start = cur;
8680 while (cur != NULL) {
8681 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008682 if ((partitions->triage != NULL) &&
8683 (partitions->flags & IS_DETERMINIST)) {
8684 void *tmp = NULL;
8685
8686 if ((cur->type == XML_TEXT_NODE) ||
8687 (cur->type == XML_CDATA_SECTION_NODE)) {
8688 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8689 NULL);
8690 } else if (cur->type == XML_ELEMENT_NODE) {
8691 if (cur->ns != NULL) {
8692 tmp = xmlHashLookup2(partitions->triage, cur->name,
8693 cur->ns->href);
8694 if (tmp == NULL)
8695 tmp = xmlHashLookup2(partitions->triage,
8696 BAD_CAST "#any", cur->ns->href);
8697 } else
8698 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
8699 if (tmp == NULL)
8700 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
8701 NULL);
8702 }
8703
8704 if (tmp == NULL) {
8705 i = nbgroups;
8706 } else {
8707 i = ((long) tmp) - 1;
8708 if (partitions->flags & IS_NEEDCHECK) {
8709 group = partitions->groups[i];
8710 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
8711 i = nbgroups;
8712 }
8713 }
8714 } else {
8715 for (i = 0;i < nbgroups;i++) {
8716 group = partitions->groups[i];
8717 if (group == NULL)
8718 continue;
8719 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
8720 break;
8721 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008722 }
8723 /*
8724 * We break as soon as an element not matched is found
8725 */
8726 if (i >= nbgroups) {
8727 break;
8728 }
8729 if (lasts[i] != NULL) {
8730 lasts[i]->next = cur;
8731 lasts[i] = cur;
8732 } else {
8733 list[i] = cur;
8734 lasts[i] = cur;
8735 }
8736 if (cur->next != NULL)
8737 lastchg = cur->next;
8738 else
8739 lastchg = cur;
8740 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
8741 }
8742 if (ret != 0) {
8743 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8744 ret = -1;
8745 goto done;
8746 }
8747 lastelem = cur;
8748 oldstate = ctxt->state;
8749 for (i = 0;i < nbgroups;i++) {
8750 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
8751 group = partitions->groups[i];
8752 if (lasts[i] != NULL) {
8753 last = lasts[i]->next;
8754 lasts[i]->next = NULL;
8755 }
8756 ctxt->state->seq = list[i];
8757 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
8758 if (ret != 0)
8759 break;
8760 if (ctxt->state != NULL) {
8761 cur = ctxt->state->seq;
8762 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00008763 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008764 oldstate = ctxt->state;
8765 ctxt->state = NULL;
8766 if (cur != NULL) {
8767 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8768 ret = -1;
8769 ctxt->state = oldstate;
8770 goto done;
8771 }
8772 } else if (ctxt->states != NULL) {
8773 int j;
8774 int found = 0;
8775
8776 for (j = 0;j < ctxt->states->nbState;j++) {
8777 cur = ctxt->states->tabState[j]->seq;
8778 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8779 if (cur == NULL) {
8780 found = 1;
8781 break;
8782 }
8783 }
8784 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008785 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008786 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
8787 }
8788 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008789 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008790 }
8791 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8792 ctxt->states = NULL;
8793 if (found == 0) {
8794 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8795 ret = -1;
8796 ctxt->state = oldstate;
8797 goto done;
8798 }
8799 } else {
8800 ret = -1;
8801 break;
8802 }
8803 if (lasts[i] != NULL) {
8804 lasts[i]->next = last;
8805 }
8806 }
8807 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008808 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008809 ctxt->state = oldstate;
8810 ctxt->state->seq = lastelem;
8811 if (ret != 0) {
8812 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8813 ret = -1;
8814 goto done;
8815 }
8816
8817done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008818 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008819 /*
8820 * builds the next links chain from the prev one
8821 */
8822 cur = lastchg;
8823 while (cur != NULL) {
8824 if ((cur == start) || (cur->prev == NULL))
8825 break;
8826 cur->prev->next = cur;
8827 cur = cur->prev;
8828 }
8829 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008830 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008831 }
8832
8833 xmlFree(list);
8834 xmlFree(lasts);
8835 return(ret);
8836}
8837
8838/**
8839 * xmlRelaxNGValidateDefinitionList:
8840 * @ctxt: a Relax-NG validation context
8841 * @define: the list of definition to verify
8842 *
8843 * Validate the given node content against the (list) of definitions
8844 *
8845 * Returns 0 if the validation succeeded or an error code.
8846 */
8847static int
8848xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
8849 xmlRelaxNGDefinePtr defines) {
8850 int ret = 0, res;
8851
8852
Daniel Veillard952379b2003-03-17 15:37:12 +00008853 if (defines == NULL) {
8854 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
8855 return(-1);
8856 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008857 while (defines != NULL) {
8858 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8859 res = xmlRelaxNGValidateDefinition(ctxt, defines);
8860 if (res < 0)
8861 ret = -1;
8862 } else {
8863 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8864 return(-1);
8865 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008866 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00008867 break;
8868 defines = defines->next;
8869 }
8870
8871 return(ret);
8872}
8873
8874/**
8875 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00008876 * @ctxt: a Relax-NG validation context
8877 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00008878 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00008879 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008880 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00008881 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008882 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00008883 */
8884static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008885xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
8886 xmlRelaxNGDefinePtr define,
8887 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008888 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008889
Daniel Veillardfd573f12003-03-16 17:52:32 +00008890 if (define->name != NULL) {
8891 if (!xmlStrEqual(elem->name, define->name)) {
8892 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
8893 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008894 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008895 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008896 if ((define->ns != NULL) && (define->ns[0] != 0)) {
8897 if (elem->ns == NULL) {
8898 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
8899 elem->name);
8900 return(0);
8901 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
8902 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
8903 elem->name, define->ns);
8904 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008905 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008906 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
8907 (define->name == NULL)) {
8908 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8909 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008910 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008911 } else if ((elem->ns != NULL) && (define->name != NULL)) {
8912 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8913 define->name);
8914 return(0);
8915 }
8916
8917 if (define->nameClass == NULL)
8918 return(1);
8919
8920 define = define->nameClass;
8921 if (define->type == XML_RELAXNG_EXCEPT) {
8922 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008923 if (ctxt != NULL) {
8924 oldflags = ctxt->flags;
8925 ctxt->flags |= FLAGS_IGNORABLE;
8926 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008927
8928 list = define->content;
8929 while (list != NULL) {
8930 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8931 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008932 if (ctxt != NULL)
8933 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008934 return(0);
8935 }
8936 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008937 if (ctxt != NULL)
8938 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008939 return(ret);
8940 }
8941 list = list->next;
8942 }
8943 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008944 if (ctxt != NULL) {
8945 ctxt->flags = oldflags;
8946 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008947 } else if (define->type == XML_RELAXNG_CHOICE) {
8948 xmlRelaxNGDefinePtr list;
8949
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008950 if (ctxt != NULL) {
8951 oldflags = ctxt->flags;
8952 ctxt->flags |= FLAGS_IGNORABLE;
8953 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008954
8955 list = define->nameClass;
8956 while (list != NULL) {
8957 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8958 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008959 if (ctxt != NULL)
8960 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008961 return(1);
8962 }
8963 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008964 if (ctxt != NULL)
8965 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008966 return(ret);
8967 }
8968 list = list->next;
8969 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008970 if (ctxt != NULL) {
8971 if (ret != 0) {
8972 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8973 xmlRelaxNGDumpValidError(ctxt);
8974 } else {
8975 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8976 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008977 }
8978 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008979 if (ctxt != NULL) {
8980 ctxt->flags = oldflags;
8981 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008982 } else {
8983 TODO
8984 ret = -1;
8985 }
8986 return(ret);
8987}
8988
8989/**
8990 * xmlRelaxNGValidateElementEnd:
8991 * @ctxt: a Relax-NG validation context
8992 *
8993 * Validate the end of the element, implements check that
8994 * there is nothing left not consumed in the element content
8995 * or in the attribute list.
8996 *
8997 * Returns 0 if the validation succeeded or an error code.
8998 */
8999static int
9000xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
9001 int ret = 0, i;
9002 xmlRelaxNGValidStatePtr state;
9003
9004 state = ctxt->state;
9005 if (state->seq != NULL) {
9006 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9007 if (state->seq != NULL) {
9008 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9009 state->node->name, state->seq->name);
9010 ret = -1;
9011 }
9012 }
9013 for (i = 0;i < state->nbAttrs;i++) {
9014 if (state->attrs[i] != NULL) {
9015 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9016 state->attrs[i]->name, state->node->name);
9017 ret = -1;
9018 }
9019 }
9020 return(ret);
9021}
9022
9023/**
9024 * xmlRelaxNGValidateState:
9025 * @ctxt: a Relax-NG validation context
9026 * @define: the definition to verify
9027 *
9028 * Validate the current state against the definition
9029 *
9030 * Returns 0 if the validation succeeded or an error code.
9031 */
9032static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009033xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9034 xmlRelaxNGDefinePtr define)
9035{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009036 xmlNodePtr node;
9037 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009038 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009039
9040 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009041 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9042 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009043 }
9044
9045 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009046 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009047 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009048 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009049 }
9050#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009051 for (i = 0; i < ctxt->depth; i++)
9052 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009054 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009055 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009056 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009057 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009058 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009059 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009060 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009061#endif
9062 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009063 switch (define->type) {
9064 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009065 node = xmlRelaxNGSkipIgnored(ctxt, node);
9066 ret = 0;
9067 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009068 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009069 ret = -1;
9070 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009071 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009072 while ((node != NULL) &&
9073 ((node->type == XML_TEXT_NODE) ||
9074 (node->type == XML_COMMENT_NODE) ||
9075 (node->type == XML_PI_NODE) ||
9076 (node->type == XML_CDATA_SECTION_NODE)))
9077 node = node->next;
9078 ctxt->state->seq = node;
9079 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009080 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009081 errNr = ctxt->errNr;
9082 node = xmlRelaxNGSkipIgnored(ctxt, node);
9083 if (node == NULL) {
9084 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9085 ret = -1;
9086 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9087 xmlRelaxNGDumpValidError(ctxt);
9088 break;
9089 }
9090 if (node->type != XML_ELEMENT_NODE) {
9091 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9092 ret = -1;
9093 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9094 xmlRelaxNGDumpValidError(ctxt);
9095 break;
9096 }
9097 /*
9098 * This node was already validated successfully against
9099 * this definition.
9100 */
9101 if (node->_private == define) {
9102 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9103 if (ctxt->errNr > errNr)
9104 xmlRelaxNGPopErrors(ctxt, errNr);
9105 if (ctxt->errNr != 0) {
9106 while ((ctxt->err != NULL) &&
9107 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9108 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9109 ||
9110 ((ctxt->err->err ==
9111 XML_RELAXNG_ERR_ELEMEXTRANS)
9112 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9113 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9114 || (ctxt->err->err ==
9115 XML_RELAXNG_ERR_NOTELEM)))
9116 xmlRelaxNGValidErrorPop(ctxt);
9117 }
9118 break;
9119 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009120
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009121 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9122 if (ret <= 0) {
9123 ret = -1;
9124 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9125 xmlRelaxNGDumpValidError(ctxt);
9126 break;
9127 }
9128 ret = 0;
9129 if (ctxt->errNr != 0) {
9130 if (ctxt->errNr > errNr)
9131 xmlRelaxNGPopErrors(ctxt, errNr);
9132 while ((ctxt->err != NULL) &&
9133 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9134 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9135 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9136 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9137 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9138 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9139 xmlRelaxNGValidErrorPop(ctxt);
9140 }
9141 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009142
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009143 oldflags = ctxt->flags;
9144 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9145 ctxt->flags -= FLAGS_MIXED_CONTENT;
9146 }
9147 state = xmlRelaxNGNewValidState(ctxt, node);
9148 if (state == NULL) {
9149 ret = -1;
9150 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9151 xmlRelaxNGDumpValidError(ctxt);
9152 break;
9153 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009154
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009155 oldstate = ctxt->state;
9156 ctxt->state = state;
9157 if (define->attrs != NULL) {
9158 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9159 if (tmp != 0) {
9160 ret = -1;
9161 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9162 }
9163 }
9164 if (define->contModel != NULL) {
9165 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9166 define->contModel,
9167 ctxt->state->seq);
9168#ifdef DEBUG_COMPILE
9169 xmlGenericError(xmlGenericErrorContext,
9170 "Validating content of '%s' : %d\n", define->name, tmp);
9171#endif
9172 state = ctxt->state;
9173 if (tmp == 0) {
9174 tmp = xmlRelaxNGValidateElementEnd(ctxt);
9175 if (tmp != 0)
9176 ret = -1;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009177 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009178 ret = -1;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009179 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009180 xmlRelaxNGFreeValidState(ctxt, state);
9181 } else {
9182 if (define->content != NULL) {
9183 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9184 define->content);
9185 if (tmp != 0) {
9186 ret = -1;
9187 if (ctxt->state == NULL) {
9188 ctxt->state = oldstate;
9189 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9190 node->name);
9191 ctxt->state = NULL;
9192 } else {
9193 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9194 node->name);
9195 }
9196
9197 }
9198 }
9199 if (ctxt->states != NULL) {
9200 tmp = -1;
9201
9202 ctxt->flags |= FLAGS_IGNORABLE;
9203
9204 for (i = 0; i < ctxt->states->nbState; i++) {
9205 state = ctxt->states->tabState[i];
9206 ctxt->state = state;
9207
9208 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9209 tmp = 0;
9210 xmlRelaxNGFreeValidState(ctxt, state);
9211 }
9212 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9213 ctxt->flags = oldflags;
9214 ctxt->states = NULL;
9215 if ((ret == 0) && (tmp == -1))
9216 ret = -1;
9217 } else {
9218 state = ctxt->state;
9219 if (ret == 0)
9220 ret = xmlRelaxNGValidateElementEnd(ctxt);
9221 xmlRelaxNGFreeValidState(ctxt, state);
9222 }
9223 }
9224 if (ret == 0) {
9225 node->_private = define;
9226 }
9227 ctxt->flags = oldflags;
9228 ctxt->state = oldstate;
9229 if (oldstate != NULL)
9230 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9231 if (ret != 0) {
9232 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9233 xmlRelaxNGDumpValidError(ctxt);
9234 ret = 0;
9235 } else {
9236 ret = -2;
9237 }
9238 } else {
9239 if (ctxt->errNr > errNr)
9240 xmlRelaxNGPopErrors(ctxt, errNr);
9241 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009242
9243#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009244 xmlGenericError(xmlGenericErrorContext,
9245 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9246 node->name, ret);
9247 if (oldstate == NULL)
9248 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9249 else if (oldstate->seq == NULL)
9250 xmlGenericError(xmlGenericErrorContext, ": done\n");
9251 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9252 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9253 oldstate->seq->name);
9254 else
9255 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9256 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009257#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009258 break;
9259 case XML_RELAXNG_OPTIONAL:{
9260 errNr = ctxt->errNr;
9261 oldflags = ctxt->flags;
9262 ctxt->flags |= FLAGS_IGNORABLE;
9263 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9264 ret =
9265 xmlRelaxNGValidateDefinitionList(ctxt,
9266 define->content);
9267 if (ret != 0) {
9268 if (ctxt->state != NULL)
9269 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9270 ctxt->state = oldstate;
9271 ctxt->flags = oldflags;
9272 ret = 0;
9273 if (ctxt->errNr > errNr)
9274 xmlRelaxNGPopErrors(ctxt, errNr);
9275 break;
9276 }
9277 if (ctxt->states != NULL) {
9278 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9279 } else {
9280 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9281 if (ctxt->states == NULL) {
9282 xmlRelaxNGFreeValidState(ctxt, oldstate);
9283 ctxt->flags = oldflags;
9284 ret = -1;
9285 if (ctxt->errNr > errNr)
9286 xmlRelaxNGPopErrors(ctxt, errNr);
9287 break;
9288 }
9289 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9290 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9291 ctxt->state = NULL;
9292 }
9293 ctxt->flags = oldflags;
9294 ret = 0;
9295 if (ctxt->errNr > errNr)
9296 xmlRelaxNGPopErrors(ctxt, errNr);
9297 break;
9298 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009299 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009300 errNr = ctxt->errNr;
9301 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9302 if (ret != 0) {
9303 break;
9304 }
9305 if (ctxt->errNr > errNr)
9306 xmlRelaxNGPopErrors(ctxt, errNr);
9307 /* no break on purpose */
9308 case XML_RELAXNG_ZEROORMORE:{
9309 int progress;
9310 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9311 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009312
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009313 errNr = ctxt->errNr;
9314 res = xmlRelaxNGNewStates(ctxt, 1);
9315 if (res == NULL) {
9316 ret = -1;
9317 break;
9318 }
9319 /*
9320 * All the input states are also exit states
9321 */
9322 if (ctxt->state != NULL) {
9323 xmlRelaxNGAddStates(ctxt, res,
9324 xmlRelaxNGCopyValidState(ctxt,
9325 ctxt->
9326 state));
9327 } else {
9328 for (j = 0; j < ctxt->states->nbState; j++) {
9329 xmlRelaxNGAddStates(ctxt, res,
9330 xmlRelaxNGCopyValidState(ctxt,
9331 ctxt->
9332 states->
9333 tabState
9334 [j]));
9335 }
9336 }
9337 oldflags = ctxt->flags;
9338 ctxt->flags |= FLAGS_IGNORABLE;
9339 do {
9340 progress = 0;
9341 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009342
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009343 if (ctxt->states != NULL) {
9344 states = ctxt->states;
9345 for (i = 0; i < states->nbState; i++) {
9346 ctxt->state = states->tabState[i];
9347 ctxt->states = NULL;
9348 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9349 define->
9350 content);
9351 if (ret == 0) {
9352 if (ctxt->state != NULL) {
9353 tmp = xmlRelaxNGAddStates(ctxt, res,
9354 ctxt->state);
9355 ctxt->state = NULL;
9356 if (tmp == 1)
9357 progress = 1;
9358 } else if (ctxt->states != NULL) {
9359 for (j = 0; j < ctxt->states->nbState;
9360 j++) {
9361 tmp =
9362 xmlRelaxNGAddStates(ctxt, res,
9363 ctxt->
9364 states->
9365 tabState
9366 [j]);
9367 if (tmp == 1)
9368 progress = 1;
9369 }
9370 xmlRelaxNGFreeStates(ctxt,
9371 ctxt->states);
9372 ctxt->states = NULL;
9373 }
9374 } else {
9375 if (ctxt->state != NULL) {
9376 xmlRelaxNGFreeValidState(ctxt,
9377 ctxt->state);
9378 ctxt->state = NULL;
9379 }
9380 }
9381 }
9382 } else {
9383 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9384 define->
9385 content);
9386 if (ret != 0) {
9387 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9388 ctxt->state = NULL;
9389 } else {
9390 base = res->nbState;
9391 if (ctxt->state != NULL) {
9392 tmp = xmlRelaxNGAddStates(ctxt, res,
9393 ctxt->state);
9394 ctxt->state = NULL;
9395 if (tmp == 1)
9396 progress = 1;
9397 } else if (ctxt->states != NULL) {
9398 for (j = 0; j < ctxt->states->nbState; j++) {
9399 tmp = xmlRelaxNGAddStates(ctxt, res,
9400 ctxt->
9401 states->
9402 tabState[j]);
9403 if (tmp == 1)
9404 progress = 1;
9405 }
9406 if (states == NULL) {
9407 states = ctxt->states;
9408 } else {
9409 xmlRelaxNGFreeStates(ctxt,
9410 ctxt->states);
9411 }
9412 ctxt->states = NULL;
9413 }
9414 }
9415 }
9416 if (progress) {
9417 /*
9418 * Collect all the new nodes added at that step
9419 * and make them the new node set
9420 */
9421 if (res->nbState - base == 1) {
9422 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9423 res->
9424 tabState
9425 [base]);
9426 } else {
9427 if (states == NULL) {
9428 xmlRelaxNGNewStates(ctxt,
9429 res->nbState - base);
9430 }
9431 states->nbState = 0;
9432 for (i = base; i < res->nbState; i++)
9433 xmlRelaxNGAddStates(ctxt, states,
9434 xmlRelaxNGCopyValidState
9435 (ctxt,
9436 res->tabState[i]));
9437 ctxt->states = states;
9438 }
9439 }
9440 } while (progress == 1);
9441 if (states != NULL) {
9442 xmlRelaxNGFreeStates(ctxt, states);
9443 }
9444 ctxt->states = res;
9445 ctxt->flags = oldflags;
9446 if (ctxt->errNr > errNr)
9447 xmlRelaxNGPopErrors(ctxt, errNr);
9448 ret = 0;
9449 break;
9450 }
9451 case XML_RELAXNG_CHOICE:{
9452 xmlRelaxNGDefinePtr list = NULL;
9453 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009454
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009455 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009456
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009457 errNr = ctxt->errNr;
9458 if ((define->dflags & IS_TRIABLE)
9459 && (define->data != NULL)) {
9460 xmlHashTablePtr triage =
9461 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +00009462
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009463 /*
9464 * Something we can optimize cleanly there is only one
9465 * possble branch out !
9466 */
9467 if (node == NULL) {
9468 ret = -1;
9469 break;
9470 }
9471 if ((node->type == XML_TEXT_NODE) ||
9472 (node->type == XML_CDATA_SECTION_NODE)) {
9473 list =
9474 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9475 } else if (node->type == XML_ELEMENT_NODE) {
9476 if (node->ns != NULL) {
9477 list = xmlHashLookup2(triage, node->name,
9478 node->ns->href);
9479 if (list == NULL)
9480 list =
9481 xmlHashLookup2(triage, BAD_CAST "#any",
9482 node->ns->href);
9483 } else
9484 list =
9485 xmlHashLookup2(triage, node->name, NULL);
9486 if (list == NULL)
9487 list =
9488 xmlHashLookup2(triage, BAD_CAST "#any",
9489 NULL);
9490 }
9491 if (list == NULL) {
9492 ret = -1;
9493 break;
9494 }
9495 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9496 if (ret == 0) {
9497 }
9498 break;
9499 }
Daniel Veillarde063f482003-03-21 16:53:17 +00009500
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009501 list = define->content;
9502 oldflags = ctxt->flags;
9503 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009504
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009505 while (list != NULL) {
9506 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9507 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9508 if (ret == 0) {
9509 if (states == NULL) {
9510 states = xmlRelaxNGNewStates(ctxt, 1);
9511 }
9512 if (ctxt->state != NULL) {
9513 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9514 } else if (ctxt->states != NULL) {
9515 for (i = 0; i < ctxt->states->nbState; i++) {
9516 xmlRelaxNGAddStates(ctxt, states,
9517 ctxt->states->
9518 tabState[i]);
9519 }
9520 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9521 ctxt->states = NULL;
9522 }
9523 } else {
9524 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9525 }
9526 ctxt->state = oldstate;
9527 list = list->next;
9528 }
9529 if (states != NULL) {
9530 xmlRelaxNGFreeValidState(ctxt, oldstate);
9531 ctxt->states = states;
9532 ctxt->state = NULL;
9533 ret = 0;
9534 } else {
9535 ctxt->states = NULL;
9536 }
9537 ctxt->flags = oldflags;
9538 if (ret != 0) {
9539 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9540 xmlRelaxNGDumpValidError(ctxt);
9541 }
9542 } else {
9543 if (ctxt->errNr > errNr)
9544 xmlRelaxNGPopErrors(ctxt, errNr);
9545 }
9546 break;
9547 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009548 case XML_RELAXNG_DEF:
9549 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009550 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9551 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009552 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009553 ret = xmlRelaxNGValidateInterleave(ctxt, define);
9554 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009555 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009556 ret = xmlRelaxNGValidateAttribute(ctxt, define);
9557 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +00009558 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009559 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00009560 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009561 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +00009562 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009563 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9564 break;
9565 case XML_RELAXNG_DATATYPE:{
9566 xmlNodePtr child;
9567 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009568
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009569 child = node;
9570 while (child != NULL) {
9571 if (child->type == XML_ELEMENT_NODE) {
9572 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9573 node->parent->name);
9574 ret = -1;
9575 break;
9576 } else if ((child->type == XML_TEXT_NODE) ||
9577 (child->type == XML_CDATA_SECTION_NODE)) {
9578 content = xmlStrcat(content, child->content);
9579 }
9580 /* TODO: handle entities ... */
9581 child = child->next;
9582 }
9583 if (ret == -1) {
9584 if (content != NULL)
9585 xmlFree(content);
9586 break;
9587 }
9588 if (content == NULL) {
9589 content = xmlStrdup(BAD_CAST "");
9590 if (content == NULL) {
9591 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9592 ret = -1;
9593 break;
9594 }
9595 }
9596 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9597 ctxt->state->seq);
9598 if (ret == -1) {
9599 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9600 } else if (ret == 0) {
9601 ctxt->state->seq = NULL;
9602 }
9603 if (content != NULL)
9604 xmlFree(content);
9605 break;
9606 }
9607 case XML_RELAXNG_VALUE:{
9608 xmlChar *content = NULL;
9609 xmlChar *oldvalue;
9610 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009611
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009612 child = node;
9613 while (child != NULL) {
9614 if (child->type == XML_ELEMENT_NODE) {
9615 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9616 node->parent->name);
9617 ret = -1;
9618 break;
9619 } else if ((child->type == XML_TEXT_NODE) ||
9620 (child->type == XML_CDATA_SECTION_NODE)) {
9621 content = xmlStrcat(content, child->content);
9622 }
9623 /* TODO: handle entities ... */
9624 child = child->next;
9625 }
9626 if (ret == -1) {
9627 if (content != NULL)
9628 xmlFree(content);
9629 break;
9630 }
9631 if (content == NULL) {
9632 content = xmlStrdup(BAD_CAST "");
9633 if (content == NULL) {
9634 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9635 ret = -1;
9636 break;
9637 }
9638 }
9639 oldvalue = ctxt->state->value;
9640 ctxt->state->value = content;
9641 ret = xmlRelaxNGValidateValue(ctxt, define);
9642 ctxt->state->value = oldvalue;
9643 if (ret == -1) {
9644 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9645 } else if (ret == 0) {
9646 ctxt->state->seq = NULL;
9647 }
9648 if (content != NULL)
9649 xmlFree(content);
9650 break;
9651 }
9652 case XML_RELAXNG_LIST:{
9653 xmlChar *content;
9654 xmlNodePtr child;
9655 xmlChar *oldvalue, *oldendvalue;
9656 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009657
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009658 /*
9659 * Make sure it's only text nodes
9660 */
9661
9662 content = NULL;
9663 child = node;
9664 while (child != NULL) {
9665 if (child->type == XML_ELEMENT_NODE) {
9666 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
9667 node->parent->name);
9668 ret = -1;
9669 break;
9670 } else if ((child->type == XML_TEXT_NODE) ||
9671 (child->type == XML_CDATA_SECTION_NODE)) {
9672 content = xmlStrcat(content, child->content);
9673 }
9674 /* TODO: handle entities ... */
9675 child = child->next;
9676 }
9677 if (ret == -1) {
9678 if (content != NULL)
9679 xmlFree(content);
9680 break;
9681 }
9682 if (content == NULL) {
9683 content = xmlStrdup(BAD_CAST "");
9684 if (content == NULL) {
9685 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9686 ret = -1;
9687 break;
9688 }
9689 }
9690 len = xmlStrlen(content);
9691 oldvalue = ctxt->state->value;
9692 oldendvalue = ctxt->state->endvalue;
9693 ctxt->state->value = content;
9694 ctxt->state->endvalue = content + len;
9695 ret = xmlRelaxNGValidateValue(ctxt, define);
9696 ctxt->state->value = oldvalue;
9697 ctxt->state->endvalue = oldendvalue;
9698 if (ret == -1) {
9699 VALID_ERR(XML_RELAXNG_ERR_LIST);
9700 } else if ((ret == 0) && (node != NULL)) {
9701 ctxt->state->seq = node->next;
9702 }
9703 if (content != NULL)
9704 xmlFree(content);
9705 break;
9706 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009707 case XML_RELAXNG_EXCEPT:
9708 case XML_RELAXNG_PARAM:
9709 TODO ret = -1;
9710 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009711 }
9712 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009713#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009714 for (i = 0; i < ctxt->depth; i++)
9715 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009716 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009717 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009718 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009719 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009720 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009721 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009722 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009723 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009724#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009725 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009726}
9727
9728/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009729 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009730 * @ctxt: a Relax-NG validation context
9731 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009732 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009733 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009734 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009735 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009736 */
9737static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009738xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
9739 xmlRelaxNGDefinePtr define) {
9740 xmlRelaxNGStatesPtr states, res;
9741 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009742
Daniel Veillardfd573f12003-03-16 17:52:32 +00009743 /*
9744 * We should NOT have both ctxt->state and ctxt->states
9745 */
9746 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9747 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009748 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009749 ctxt->state = NULL;
9750 }
9751
9752 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
9753 if (ctxt->states != NULL) {
9754 ctxt->state = ctxt->states->tabState[0];
9755 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9756 ctxt->states = NULL;
9757 }
9758 ret = xmlRelaxNGValidateState(ctxt, define);
9759 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9760 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009761 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009762 ctxt->state = NULL;
9763 }
9764 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
9765 ctxt->state = ctxt->states->tabState[0];
9766 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9767 ctxt->states = NULL;
9768 }
9769 return(ret);
9770 }
9771
9772 states = ctxt->states;
9773 ctxt->states = NULL;
9774 res = NULL;
9775 j = 0;
9776 oldflags = ctxt->flags;
9777 ctxt->flags |= FLAGS_IGNORABLE;
9778 for (i = 0;i < states->nbState;i++) {
9779 ctxt->state = states->tabState[i];
9780 ctxt->states = NULL;
9781 ret = xmlRelaxNGValidateState(ctxt, define);
9782 /*
9783 * We should NOT have both ctxt->state and ctxt->states
9784 */
9785 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9786 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009787 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009788 ctxt->state = NULL;
9789 }
9790 if (ret == 0) {
9791 if (ctxt->states == NULL) {
9792 if (res != NULL) {
9793 /* add the state to the container */
9794 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
9795 ctxt->state = NULL;
9796 } else {
9797 /* add the state directly in states */
9798 states->tabState[j++] = ctxt->state;
9799 ctxt->state = NULL;
9800 }
9801 } else {
9802 if (res == NULL) {
9803 /* make it the new container and copy other results */
9804 res = ctxt->states;
9805 ctxt->states = NULL;
9806 for (k = 0;k < j;k++)
9807 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
9808 } else {
9809 /* add all the new results to res and reff the container */
9810 for (k = 0;k < ctxt->states->nbState;k++)
9811 xmlRelaxNGAddStates(ctxt, res,
9812 ctxt->states->tabState[k]);
9813 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9814 ctxt->states = NULL;
9815 }
9816 }
9817 } else {
9818 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009819 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009820 ctxt->state = NULL;
9821 } else if (ctxt->states != NULL) {
9822 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00009823 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009824 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9825 ctxt->states = NULL;
9826 }
9827 }
9828 }
9829 ctxt->flags = oldflags;
9830 if (res != NULL) {
9831 xmlRelaxNGFreeStates(ctxt, states);
9832 ctxt->states = res;
9833 ret = 0;
9834 } else if (j > 1) {
9835 states->nbState = j;
9836 ctxt->states = states;
9837 ret =0;
9838 } else if (j == 1) {
9839 ctxt->state = states->tabState[0];
9840 xmlRelaxNGFreeStates(ctxt, states);
9841 ret = 0;
9842 } else {
9843 ret = -1;
9844 xmlRelaxNGFreeStates(ctxt, states);
9845 if (ctxt->states != NULL) {
9846 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9847 ctxt->states = NULL;
9848 }
9849 }
9850 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9851 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009852 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009853 ctxt->state = NULL;
9854 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009855 return(ret);
9856}
9857
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009858/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00009859 * xmlRelaxNGValidateDocument:
9860 * @ctxt: a Relax-NG validation context
9861 * @doc: the document
9862 *
9863 * Validate the given document
9864 *
9865 * Returns 0 if the validation succeeded or an error code.
9866 */
9867static int
9868xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9869 int ret;
9870 xmlRelaxNGPtr schema;
9871 xmlRelaxNGGrammarPtr grammar;
9872 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009873 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009874
9875 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
9876 return(-1);
9877
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009878 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009879 schema = ctxt->schema;
9880 grammar = schema->topgrammar;
9881 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00009882 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009883 return(-1);
9884 }
9885 state = xmlRelaxNGNewValidState(ctxt, NULL);
9886 ctxt->state = state;
9887 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009888 if ((ctxt->state != NULL) && (state->seq != NULL)) {
9889 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009890 node = state->seq;
9891 node = xmlRelaxNGSkipIgnored(ctxt, node);
9892 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00009893 if (ret != -1) {
9894 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
9895 ret = -1;
9896 }
9897 }
9898 } else if (ctxt->states != NULL) {
9899 int i;
9900 int tmp = -1;
9901
9902 for (i = 0;i < ctxt->states->nbState;i++) {
9903 state = ctxt->states->tabState[i];
9904 node = state->seq;
9905 node = xmlRelaxNGSkipIgnored(ctxt, node);
9906 if (node == NULL)
9907 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00009908 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009909 }
9910 if (tmp == -1) {
9911 if (ret != -1) {
9912 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
9913 ret = -1;
9914 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009915 }
9916 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009917 if (ctxt->state != NULL) {
9918 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9919 ctxt->state = NULL;
9920 }
Daniel Veillard580ced82003-03-21 21:22:48 +00009921 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00009922 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00009923#ifdef DEBUG
9924 else if (ctxt->errNr != 0) {
9925 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
9926 ctxt->errNr);
9927 xmlRelaxNGDumpValidError(ctxt);
9928 }
9929#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009930 if (ctxt->idref == 1) {
9931 xmlValidCtxt vctxt;
9932
9933 memset(&vctxt, 0, sizeof(xmlValidCtxt));
9934 vctxt.valid = 1;
9935 vctxt.error = ctxt->error;
9936 vctxt.warning = ctxt->warning;
9937 vctxt.userData = ctxt->userData;
9938
9939 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
9940 ret = -1;
9941 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009942 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
9943 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009944
9945 return(ret);
9946}
9947
Daniel Veillardfd573f12003-03-16 17:52:32 +00009948/************************************************************************
9949 * *
9950 * Validation interfaces *
9951 * *
9952 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00009953/**
9954 * xmlRelaxNGNewValidCtxt:
9955 * @schema: a precompiled XML RelaxNGs
9956 *
9957 * Create an XML RelaxNGs validation context based on the given schema
9958 *
9959 * Returns the validation context or NULL in case of error
9960 */
9961xmlRelaxNGValidCtxtPtr
9962xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
9963 xmlRelaxNGValidCtxtPtr ret;
9964
9965 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
9966 if (ret == NULL) {
9967 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00009968 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00009969 return (NULL);
9970 }
9971 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
9972 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00009973 ret->error = xmlGenericError;
9974 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00009975 ret->errNr = 0;
9976 ret->errMax = 0;
9977 ret->err = NULL;
9978 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009979 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00009980 ret->states = NULL;
9981 ret->freeState = NULL;
9982 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009983 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009984 return (ret);
9985}
9986
9987/**
9988 * xmlRelaxNGFreeValidCtxt:
9989 * @ctxt: the schema validation context
9990 *
9991 * Free the resources associated to the schema validation context
9992 */
9993void
9994xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009995 int k;
9996
Daniel Veillard6eadf632003-01-23 18:29:16 +00009997 if (ctxt == NULL)
9998 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009999 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +000010000 xmlRelaxNGFreeStates(NULL, ctxt->states);
10001 if (ctxt->freeState != NULL) {
10002 for (k = 0;k < ctxt->freeState->nbState;k++) {
10003 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10004 }
10005 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10006 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010007 if (ctxt->freeStates != NULL) {
10008 for (k = 0;k < ctxt->freeStatesNr;k++) {
10009 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10010 }
10011 xmlFree(ctxt->freeStates);
10012 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010013 if (ctxt->errTab != NULL)
10014 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010015 if (ctxt->elemTab != NULL) {
10016 xmlRegExecCtxtPtr exec;
10017
10018 exec = xmlRelaxNGElemPop(ctxt);
10019 while (exec != NULL) {
10020 xmlRegFreeExecCtxt(exec);
10021 exec = xmlRelaxNGElemPop(ctxt);
10022 }
10023 xmlFree(ctxt->elemTab);
10024 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010025 xmlFree(ctxt);
10026}
10027
10028/**
10029 * xmlRelaxNGSetValidErrors:
10030 * @ctxt: a Relax-NG validation context
10031 * @err: the error function
10032 * @warn: the warning function
10033 * @ctx: the functions context
10034 *
10035 * Set the error and warning callback informations
10036 */
10037void
10038xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10039 xmlRelaxNGValidityErrorFunc err,
10040 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
10041 if (ctxt == NULL)
10042 return;
10043 ctxt->error = err;
10044 ctxt->warning = warn;
10045 ctxt->userData = ctx;
10046}
10047
10048/**
10049 * xmlRelaxNGValidateDoc:
10050 * @ctxt: a Relax-NG validation context
10051 * @doc: a parsed document tree
10052 *
10053 * Validate a document tree in memory.
10054 *
10055 * Returns 0 if the document is valid, a positive error code
10056 * number otherwise and -1 in case of internal or API error.
10057 */
10058int
10059xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10060 int ret;
10061
10062 if ((ctxt == NULL) || (doc == NULL))
10063 return(-1);
10064
10065 ctxt->doc = doc;
10066
10067 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010068 /*
10069 * TODO: build error codes
10070 */
10071 if (ret == -1)
10072 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010073 return(ret);
10074}
10075
10076#endif /* LIBXML_SCHEMAS_ENABLED */
10077