blob: f28869b4ca4e65ff413220b3f395961b9de7c12d [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 Veillard6eadf632003-01-23 18:29:16 +000058
59#define UNBOUNDED (1 << 30)
60#define TODO \
61 xmlGenericError(xmlGenericErrorContext, \
62 "Unimplemented block at %s:%d\n", \
63 __FILE__, __LINE__);
64
65typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
66typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
67
68typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
69typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
70
Daniel Veillardd41f4f42003-01-29 21:07:52 +000071typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
72typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
73
Daniel Veillarda9d912d2003-02-01 17:43:10 +000074typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
75typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
76
Daniel Veillard6eadf632003-01-23 18:29:16 +000077typedef enum {
78 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
79 XML_RELAXNG_COMBINE_CHOICE, /* choice */
80 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
81} xmlRelaxNGCombine;
82
Daniel Veillard4c5cf702003-02-21 15:40:34 +000083typedef enum {
84 XML_RELAXNG_CONTENT_ERROR = -1,
85 XML_RELAXNG_CONTENT_EMPTY = 0,
86 XML_RELAXNG_CONTENT_SIMPLE,
87 XML_RELAXNG_CONTENT_COMPLEX
88} xmlRelaxNGContentType;
89
Daniel Veillard6eadf632003-01-23 18:29:16 +000090typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
91typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
92
93struct _xmlRelaxNGGrammar {
94 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
95 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
96 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
97 xmlRelaxNGDefinePtr start; /* <start> content */
98 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +000099 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000100 xmlHashTablePtr defs; /* define* */
101 xmlHashTablePtr refs; /* references */
102};
103
104
Daniel Veillard6eadf632003-01-23 18:29:16 +0000105typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000106 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000107 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
108 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000109 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000110 XML_RELAXNG_TEXT, /* textual content */
111 XML_RELAXNG_ELEMENT, /* an element */
112 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000113 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
115 XML_RELAXNG_LIST, /* a list of patterns */
116 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
117 XML_RELAXNG_DEF, /* a definition */
118 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000119 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000120 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000121 XML_RELAXNG_OPTIONAL, /* optional patterns */
122 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000123 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
124 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
125 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000126 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000127 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000128} xmlRelaxNGType;
129
Daniel Veillardfd573f12003-03-16 17:52:32 +0000130#define IS_NULLABLE 1
131#define IS_NOT_NULLABLE 2
132#define IS_INDETERMINIST 4
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000133#define IS_MIXED 8
Daniel Veillarde063f482003-03-21 16:53:17 +0000134#define IS_TRIABLE 16
135#define IS_PROCESSED 32
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000136
Daniel Veillard6eadf632003-01-23 18:29:16 +0000137struct _xmlRelaxNGDefine {
138 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000139 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000140 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000141 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000142 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000143 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000144 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000145 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000146 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000147 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000148 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000149 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000150 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000151 short dflags; /* define related flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000152};
153
154/**
155 * _xmlRelaxNG:
156 *
157 * A RelaxNGs definition
158 */
159struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000160 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000161 xmlRelaxNGGrammarPtr topgrammar;
162 xmlDocPtr doc;
163
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000164 int idref; /* requires idref checking */
165
Daniel Veillard6eadf632003-01-23 18:29:16 +0000166 xmlHashTablePtr defs; /* define */
167 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000168 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
169 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000170 int defNr; /* number of defines used */
171 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000172
Daniel Veillard6eadf632003-01-23 18:29:16 +0000173};
174
Daniel Veillard77648bb2003-02-20 15:03:22 +0000175#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
176#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
177#define XML_RELAXNG_IN_LIST (1 << 2)
178#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
179#define XML_RELAXNG_IN_START (1 << 4)
180#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
181#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
182#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000183#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
184#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000185
186struct _xmlRelaxNGParserCtxt {
187 void *userData; /* user specific data block */
188 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
189 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000190 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000191
192 xmlRelaxNGPtr schema; /* The schema in use */
193 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000194 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000195 int flags; /* parser flags */
196 int nbErrors; /* number of errors at parse time */
197 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000198 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000199 xmlRelaxNGDefinePtr def; /* the current define */
200
201 int nbInterleaves;
202 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000203
Daniel Veillardc482e262003-02-26 14:48:48 +0000204 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
205 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000206 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000207 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000208
Daniel Veillard419a7682003-02-03 23:22:49 +0000209 int defNr; /* number of defines used */
210 int defMax; /* number of defines aloocated */
211 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
212
Daniel Veillard6eadf632003-01-23 18:29:16 +0000213 const char *buffer;
214 int size;
215
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000216 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000217 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000218 int docNr; /* Depth of the parsing stack */
219 int docMax; /* Max depth of the parsing stack */
220 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000221
222 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000223 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000224 int incNr; /* Depth of the include parsing stack */
225 int incMax; /* Max depth of the parsing stack */
226 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000227
228 int idref; /* requires idref checking */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000229};
230
231#define FLAGS_IGNORABLE 1
232#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000233#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000234
235/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000236 * xmlRelaxNGInterleaveGroup:
237 *
238 * A RelaxNGs partition set associated to lists of definitions
239 */
240typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
241typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
242struct _xmlRelaxNGInterleaveGroup {
243 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
244 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000245 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000246};
247
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000248#define IS_DETERMINIST 1
249#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000250/**
251 * xmlRelaxNGPartitions:
252 *
253 * A RelaxNGs partition associated to an interleave group
254 */
255typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
256typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
257struct _xmlRelaxNGPartition {
258 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000259 xmlHashTablePtr triage; /* hash table used to direct nodes to the
260 right group when possible */
261 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000262 xmlRelaxNGInterleaveGroupPtr *groups;
263};
264
265/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000266 * xmlRelaxNGValidState:
267 *
268 * A RelaxNGs validation state
269 */
270#define MAX_ATTR 20
271typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
272typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
273struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000274 xmlNodePtr node; /* the current node */
275 xmlNodePtr seq; /* the sequence of children left to validate */
276 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000277 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000278 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000279 xmlChar *value; /* the value when operating on string */
280 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000281 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000282};
283
284/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000285 * xmlRelaxNGStates:
286 *
287 * A RelaxNGs container for validation state
288 */
289typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
290typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
291struct _xmlRelaxNGStates {
292 int nbState; /* the number of states */
293 int maxState; /* the size of the array */
294 xmlRelaxNGValidStatePtr *tabState;
295};
296
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000297#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000298/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000299 * xmlRelaxNGValidError:
300 *
301 * A RelaxNGs validation error
302 */
303typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
304typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
305struct _xmlRelaxNGValidError {
306 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000307 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000308 xmlNodePtr node; /* the current node */
309 xmlNodePtr seq; /* the current child */
310 const xmlChar * arg1; /* first arg */
311 const xmlChar * arg2; /* second arg */
312};
313
314/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000315 * xmlRelaxNGValidCtxt:
316 *
317 * A RelaxNGs validation context
318 */
319
320struct _xmlRelaxNGValidCtxt {
321 void *userData; /* user specific data block */
322 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
323 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
324
325 xmlRelaxNGPtr schema; /* The schema in use */
326 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000327 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000328 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000329 int idref; /* requires idref checking */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000330
331 /*
332 * Errors accumulated in branches may have to be stacked to be
333 * provided back when it's sure they affect validation.
334 */
335 xmlRelaxNGValidErrorPtr err; /* Last error */
336 int errNr; /* Depth of the error stack */
337 int errMax; /* Max depth of the error stack */
338 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000339
Daniel Veillardfd573f12003-03-16 17:52:32 +0000340 xmlRelaxNGValidStatePtr state; /* the current validation state */
341 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000342
343 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
344 int freeStatesNr;
345 int freeStatesMax;
346 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000347};
348
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000349/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000350 * xmlRelaxNGInclude:
351 *
352 * Structure associated to a RelaxNGs document element
353 */
354struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000355 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000356 xmlChar *href; /* the normalized href value */
357 xmlDocPtr doc; /* the associated XML document */
358 xmlRelaxNGDefinePtr content;/* the definitions */
359 xmlRelaxNGPtr schema; /* the schema */
360};
361
362/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000363 * xmlRelaxNGDocument:
364 *
365 * Structure associated to a RelaxNGs document element
366 */
367struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000368 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000369 xmlChar *href; /* the normalized href value */
370 xmlDocPtr doc; /* the associated XML document */
371 xmlRelaxNGDefinePtr content;/* the definitions */
372 xmlRelaxNGPtr schema; /* the schema */
373};
374
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000375
Daniel Veillard6eadf632003-01-23 18:29:16 +0000376/************************************************************************
377 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000378 * Preliminary type checking interfaces *
379 * *
380 ************************************************************************/
381/**
382 * xmlRelaxNGTypeHave:
383 * @data: data needed for the library
384 * @type: the type name
385 * @value: the value to check
386 *
387 * Function provided by a type library to check if a type is exported
388 *
389 * Returns 1 if yes, 0 if no and -1 in case of error.
390 */
391typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
392
393/**
394 * xmlRelaxNGTypeCheck:
395 * @data: data needed for the library
396 * @type: the type name
397 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000398 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000399 *
400 * Function provided by a type library to check if a value match a type
401 *
402 * Returns 1 if yes, 0 if no and -1 in case of error.
403 */
404typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000405 const xmlChar *value, void **result,
406 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000407
408/**
409 * xmlRelaxNGFacetCheck:
410 * @data: data needed for the library
411 * @type: the type name
412 * @facet: the facet name
413 * @val: the facet value
414 * @strval: the string value
415 * @value: the value to check
416 *
417 * Function provided by a type library to check a value facet
418 *
419 * Returns 1 if yes, 0 if no and -1 in case of error.
420 */
421typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
422 const xmlChar *facet, const xmlChar *val,
423 const xmlChar *strval, void *value);
424
425/**
426 * xmlRelaxNGTypeFree:
427 * @data: data needed for the library
428 * @result: the value to free
429 *
430 * Function provided by a type library to free a returned result
431 */
432typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000433
434/**
435 * xmlRelaxNGTypeCompare:
436 * @data: data needed for the library
437 * @type: the type name
438 * @value1: the first value
439 * @value2: the second value
440 *
441 * Function provided by a type library to compare two values accordingly
442 * to a type.
443 *
444 * Returns 1 if yes, 0 if no and -1 in case of error.
445 */
446typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
447 const xmlChar *value1,
448 const xmlChar *value2);
449typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
450typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
451struct _xmlRelaxNGTypeLibrary {
452 const xmlChar *namespace; /* the datatypeLibrary value */
453 void *data; /* data needed for the library */
454 xmlRelaxNGTypeHave have; /* the export function */
455 xmlRelaxNGTypeCheck check; /* the checking function */
456 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000457 xmlRelaxNGFacetCheck facet; /* the facet check function */
458 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000459};
460
461/************************************************************************
462 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000463 * Allocation functions *
464 * *
465 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000466static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
467static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000468static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000469static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000470static int xmlRelaxNGEqualValidState(
471 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
472 xmlRelaxNGValidStatePtr state1,
473 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000474static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
475 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000476
477/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000478 * xmlRelaxNGFreeDocument:
479 * @docu: a document structure
480 *
481 * Deallocate a RelaxNG document structure.
482 */
483static void
484xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
485{
486 if (docu == NULL)
487 return;
488
489 if (docu->href != NULL)
490 xmlFree(docu->href);
491 if (docu->doc != NULL)
492 xmlFreeDoc(docu->doc);
493 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000494 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000495 xmlFree(docu);
496}
497
498/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000499 * xmlRelaxNGFreeDocumentList:
500 * @docu: a list of document structure
501 *
502 * Deallocate a RelaxNG document structures.
503 */
504static void
505xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
506{
507 xmlRelaxNGDocumentPtr next;
508 while (docu != NULL) {
509 next = docu->next;
510 xmlRelaxNGFreeDocument(docu);
511 docu = next;
512 }
513}
514
515/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000516 * xmlRelaxNGFreeInclude:
517 * @incl: a include structure
518 *
519 * Deallocate a RelaxNG include structure.
520 */
521static void
522xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
523{
524 if (incl == NULL)
525 return;
526
527 if (incl->href != NULL)
528 xmlFree(incl->href);
529 if (incl->doc != NULL)
530 xmlFreeDoc(incl->doc);
531 if (incl->schema != NULL)
532 xmlRelaxNGFree(incl->schema);
533 xmlFree(incl);
534}
535
536/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000537 * xmlRelaxNGFreeIncludeList:
538 * @incl: a include structure list
539 *
540 * Deallocate a RelaxNG include structure.
541 */
542static void
543xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
544{
545 xmlRelaxNGIncludePtr next;
546 while (incl != NULL) {
547 next = incl->next;
548 xmlRelaxNGFreeInclude(incl);
549 incl = next;
550 }
551}
552
553/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000554 * xmlRelaxNGNewRelaxNG:
555 * @ctxt: a Relax-NG validation context (optional)
556 *
557 * Allocate a new RelaxNG structure.
558 *
559 * Returns the newly allocated structure or NULL in case or error
560 */
561static xmlRelaxNGPtr
562xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
563{
564 xmlRelaxNGPtr ret;
565
566 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
567 if (ret == NULL) {
568 if ((ctxt != NULL) && (ctxt->error != NULL))
569 ctxt->error(ctxt->userData, "Out of memory\n");
570 ctxt->nbErrors++;
571 return (NULL);
572 }
573 memset(ret, 0, sizeof(xmlRelaxNG));
574
575 return (ret);
576}
577
578/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000579 * xmlRelaxNGFreeInnerSchema:
580 * @schema: a schema structure
581 *
582 * Deallocate a RelaxNG schema structure.
583 */
584static void
585xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
586{
587 if (schema == NULL)
588 return;
589
590 if (schema->doc != NULL)
591 xmlFreeDoc(schema->doc);
592 if (schema->defTab != NULL) {
593 int i;
594
595 for (i = 0;i < schema->defNr;i++)
596 xmlRelaxNGFreeDefine(schema->defTab[i]);
597 xmlFree(schema->defTab);
598 }
599
600 xmlFree(schema);
601}
602
603/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000604 * xmlRelaxNGFree:
605 * @schema: a schema structure
606 *
607 * Deallocate a RelaxNG structure.
608 */
609void
610xmlRelaxNGFree(xmlRelaxNGPtr schema)
611{
612 if (schema == NULL)
613 return;
614
Daniel Veillard6eadf632003-01-23 18:29:16 +0000615 if (schema->topgrammar != NULL)
616 xmlRelaxNGFreeGrammar(schema->topgrammar);
617 if (schema->doc != NULL)
618 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000619 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000620 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000621 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000622 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000623 if (schema->defTab != NULL) {
624 int i;
625
626 for (i = 0;i < schema->defNr;i++)
627 xmlRelaxNGFreeDefine(schema->defTab[i]);
628 xmlFree(schema->defTab);
629 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000630
631 xmlFree(schema);
632}
633
634/**
635 * xmlRelaxNGNewGrammar:
636 * @ctxt: a Relax-NG validation context (optional)
637 *
638 * Allocate a new RelaxNG grammar.
639 *
640 * Returns the newly allocated structure or NULL in case or error
641 */
642static xmlRelaxNGGrammarPtr
643xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
644{
645 xmlRelaxNGGrammarPtr ret;
646
647 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
648 if (ret == NULL) {
649 if ((ctxt != NULL) && (ctxt->error != NULL))
650 ctxt->error(ctxt->userData, "Out of memory\n");
651 ctxt->nbErrors++;
652 return (NULL);
653 }
654 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
655
656 return (ret);
657}
658
659/**
660 * xmlRelaxNGFreeGrammar:
661 * @grammar: a grammar structure
662 *
663 * Deallocate a RelaxNG grammar structure.
664 */
665static void
666xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
667{
668 if (grammar == NULL)
669 return;
670
Daniel Veillardc482e262003-02-26 14:48:48 +0000671 if (grammar->children != NULL) {
672 xmlRelaxNGFreeGrammar(grammar->children);
673 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000674 if (grammar->next != NULL) {
675 xmlRelaxNGFreeGrammar(grammar->next);
676 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000677 if (grammar->refs != NULL) {
678 xmlHashFree(grammar->refs, NULL);
679 }
680 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000681 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000682 }
683
684 xmlFree(grammar);
685}
686
687/**
688 * xmlRelaxNGNewDefine:
689 * @ctxt: a Relax-NG validation context
690 * @node: the node in the input document.
691 *
692 * Allocate a new RelaxNG define.
693 *
694 * Returns the newly allocated structure or NULL in case or error
695 */
696static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000697xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000698{
699 xmlRelaxNGDefinePtr ret;
700
Daniel Veillard419a7682003-02-03 23:22:49 +0000701 if (ctxt->defMax == 0) {
702 ctxt->defMax = 16;
703 ctxt->defNr = 0;
704 ctxt->defTab = (xmlRelaxNGDefinePtr *)
705 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
706 if (ctxt->defTab == NULL) {
707 if ((ctxt != NULL) && (ctxt->error != NULL))
708 ctxt->error(ctxt->userData, "Out of memory\n");
709 ctxt->nbErrors++;
710 return (NULL);
711 }
712 } else if (ctxt->defMax <= ctxt->defNr) {
713 xmlRelaxNGDefinePtr *tmp;
714 ctxt->defMax *= 2;
715 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
716 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
717 if (tmp == NULL) {
718 if ((ctxt != NULL) && (ctxt->error != NULL))
719 ctxt->error(ctxt->userData, "Out of memory\n");
720 ctxt->nbErrors++;
721 return (NULL);
722 }
723 ctxt->defTab = tmp;
724 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000725 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
726 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000727 if ((ctxt != NULL) && (ctxt->error != NULL))
728 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000729 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000730 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000731 }
732 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000733 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000734 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000735 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000736 return (ret);
737}
738
739/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000740 * xmlRelaxNGFreePartition:
741 * @partitions: a partition set structure
742 *
743 * Deallocate RelaxNG partition set structures.
744 */
745static void
746xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
747 xmlRelaxNGInterleaveGroupPtr group;
748 int j;
749
750 if (partitions != NULL) {
751 if (partitions->groups != NULL) {
752 for (j = 0;j < partitions->nbgroups;j++) {
753 group = partitions->groups[j];
754 if (group != NULL) {
755 if (group->defs != NULL)
756 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000757 if (group->attrs != NULL)
758 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000759 xmlFree(group);
760 }
761 }
762 xmlFree(partitions->groups);
763 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000764 if (partitions->triage != NULL) {
765 xmlHashFree(partitions->triage, NULL);
766 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000767 xmlFree(partitions);
768 }
769}
770/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000771 * xmlRelaxNGFreeDefine:
772 * @define: a define structure
773 *
774 * Deallocate a RelaxNG define structure.
775 */
776static void
777xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
778{
779 if (define == NULL)
780 return;
781
Daniel Veillard419a7682003-02-03 23:22:49 +0000782 if ((define->data != NULL) &&
783 (define->type == XML_RELAXNG_INTERLEAVE))
784 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000785 if ((define->data != NULL) &&
786 (define->type == XML_RELAXNG_CHOICE))
787 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000788 if (define->name != NULL)
789 xmlFree(define->name);
790 if (define->ns != NULL)
791 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000792 if (define->value != NULL)
793 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000794 xmlFree(define);
795}
796
797/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000798 * xmlRelaxNGNewStates:
799 * @ctxt: a Relax-NG validation context
800 * @size: the default size for the container
801 *
802 * Allocate a new RelaxNG validation state container
803 * TODO: keep a pool in the ctxt
804 *
805 * Returns the newly allocated structure or NULL in case or error
806 */
807static xmlRelaxNGStatesPtr
808xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
809{
810 xmlRelaxNGStatesPtr ret;
811
Daniel Veillard798024a2003-03-19 10:36:09 +0000812 if ((ctxt != NULL) &&
813 (ctxt->freeState != NULL) &&
814 (ctxt->freeStatesNr > 0)) {
815 ctxt->freeStatesNr--;
816 ret = ctxt->freeStates[ctxt->freeStatesNr];
817 ret->nbState = 0;
818 return(ret);
819 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000820 if (size < 16) size = 16;
821
822 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
823 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
824 if (ret == NULL) {
825 if ((ctxt != NULL) && (ctxt->error != NULL))
826 ctxt->error(ctxt->userData, "Out of memory\n");
827 return (NULL);
828 }
829 ret->nbState = 0;
830 ret->maxState = size;
831 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
832 (size) * sizeof(xmlRelaxNGValidStatePtr));
833 if (ret->tabState == NULL) {
834 if ((ctxt != NULL) && (ctxt->error != NULL))
835 ctxt->error(ctxt->userData, "Out of memory\n");
836 xmlFree(ret->tabState);
837 return (NULL);
838 }
839 return(ret);
840}
841
842/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000843 * xmlRelaxNGAddStateUniq:
844 * @ctxt: a Relax-NG validation context
845 * @states: the states container
846 * @state: the validation state
847 *
848 * Add a RelaxNG validation state to the container without checking
849 * for unicity.
850 *
851 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
852 */
853static int
854xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
855 xmlRelaxNGStatesPtr states,
856 xmlRelaxNGValidStatePtr state)
857{
858 if (state == NULL) {
859 return(-1);
860 }
861 if (states->nbState >= states->maxState) {
862 xmlRelaxNGValidStatePtr *tmp;
863 int size;
864
865 size = states->maxState * 2;
866 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
867 (size) * sizeof(xmlRelaxNGValidStatePtr));
868 if (tmp == NULL) {
869 if ((ctxt != NULL) && (ctxt->error != NULL))
870 ctxt->error(ctxt->userData, "Out of memory\n");
871 return(-1);
872 }
873 states->tabState = tmp;
874 states->maxState = size;
875 }
876 states->tabState[states->nbState++] = state;
877 return(1);
878}
879
880/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000881 * xmlRelaxNGAddState:
882 * @ctxt: a Relax-NG validation context
883 * @states: the states container
884 * @state: the validation state
885 *
886 * Add a RelaxNG validation state to the container
887 *
888 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
889 */
890static int
891xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
892 xmlRelaxNGValidStatePtr state)
893{
894 int i;
895
896 if (state == NULL) {
897 return(-1);
898 }
899 if (states->nbState >= states->maxState) {
900 xmlRelaxNGValidStatePtr *tmp;
901 int size;
902
903 size = states->maxState * 2;
904 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
905 (size) * sizeof(xmlRelaxNGValidStatePtr));
906 if (tmp == NULL) {
907 if ((ctxt != NULL) && (ctxt->error != NULL))
908 ctxt->error(ctxt->userData, "Out of memory\n");
909 return(-1);
910 }
911 states->tabState = tmp;
912 states->maxState = size;
913 }
914 for (i = 0;i < states->nbState;i++) {
915 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000916 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000917 return(0);
918 }
919 }
920 states->tabState[states->nbState++] = state;
921 return(1);
922}
923
924/**
925 * xmlRelaxNGFreeStates:
926 * @ctxt: a Relax-NG validation context
927 * @states: teh container
928 *
929 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000930 */
931static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000932xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000933 xmlRelaxNGStatesPtr states)
934{
Daniel Veillard798024a2003-03-19 10:36:09 +0000935 if (states == NULL)
936 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000937 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
938 ctxt->freeStatesMax = 40;
939 ctxt->freeStatesNr = 0;
940 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
941 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
942 if (ctxt->freeStates == NULL) {
943 if ((ctxt != NULL) && (ctxt->error != NULL))
944 ctxt->error(ctxt->userData, "Out of memory\n");
945 }
946 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
947 xmlRelaxNGStatesPtr *tmp;
948
949 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
950 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
951 if (tmp == NULL) {
952 if ((ctxt != NULL) && (ctxt->error != NULL))
953 ctxt->error(ctxt->userData, "Out of memory\n");
954 xmlFree(states->tabState);
955 xmlFree(states);
956 return;
957 }
958 ctxt->freeStates = tmp;
959 ctxt->freeStatesMax *= 2;
960 }
961 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000962 xmlFree(states->tabState);
963 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000964 } else {
965 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000966 }
967}
968
969/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000970 * xmlRelaxNGNewValidState:
971 * @ctxt: a Relax-NG validation context
972 * @node: the current node or NULL for the document
973 *
974 * Allocate a new RelaxNG validation state
975 *
976 * Returns the newly allocated structure or NULL in case or error
977 */
978static xmlRelaxNGValidStatePtr
979xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
980{
981 xmlRelaxNGValidStatePtr ret;
982 xmlAttrPtr attr;
983 xmlAttrPtr attrs[MAX_ATTR];
984 int nbAttrs = 0;
985 xmlNodePtr root = NULL;
986
987 if (node == NULL) {
988 root = xmlDocGetRootElement(ctxt->doc);
989 if (root == NULL)
990 return(NULL);
991 } else {
992 attr = node->properties;
993 while (attr != NULL) {
994 if (nbAttrs < MAX_ATTR)
995 attrs[nbAttrs++] = attr;
996 else
997 nbAttrs++;
998 attr = attr->next;
999 }
1000 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001001 if ((ctxt->freeState != NULL) &&
1002 (ctxt->freeState->nbState > 0)) {
1003 ctxt->freeState->nbState--;
1004 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1005 } else {
1006 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1007 if (ret == NULL) {
1008 if ((ctxt != NULL) && (ctxt->error != NULL))
1009 ctxt->error(ctxt->userData, "Out of memory\n");
1010 return (NULL);
1011 }
1012 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001013 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001014 ret->value = NULL;
1015 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001016 if (node == NULL) {
1017 ret->node = (xmlNodePtr) ctxt->doc;
1018 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001019 } else {
1020 ret->node = node;
1021 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001022 }
1023 ret->nbAttrs = 0;
1024 if (nbAttrs > 0) {
1025 if (ret->attrs == NULL) {
1026 if (nbAttrs < 4) ret->maxAttrs = 4;
1027 else ret->maxAttrs = nbAttrs;
1028 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1029 sizeof(xmlAttrPtr));
1030 if (ret->attrs == NULL) {
1031 if ((ctxt != NULL) && (ctxt->error != NULL))
1032 ctxt->error(ctxt->userData, "Out of memory\n");
1033 return (ret);
1034 }
1035 } else if (ret->maxAttrs < nbAttrs) {
1036 xmlAttrPtr *tmp;
1037
1038 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1039 sizeof(xmlAttrPtr));
1040 if (tmp == NULL) {
1041 if ((ctxt != NULL) && (ctxt->error != NULL))
1042 ctxt->error(ctxt->userData, "Out of memory\n");
1043 return (ret);
1044 }
1045 ret->attrs = tmp;
1046 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001047 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001048 if (nbAttrs < MAX_ATTR) {
1049 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1050 } else {
1051 attr = node->properties;
1052 nbAttrs = 0;
1053 while (attr != NULL) {
1054 ret->attrs[nbAttrs++] = attr;
1055 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001056 }
1057 }
1058 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001059 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001060 return (ret);
1061}
1062
1063/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001064 * xmlRelaxNGCopyValidState:
1065 * @ctxt: a Relax-NG validation context
1066 * @state: a validation state
1067 *
1068 * Copy the validation state
1069 *
1070 * Returns the newly allocated structure or NULL in case or error
1071 */
1072static xmlRelaxNGValidStatePtr
1073xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1074 xmlRelaxNGValidStatePtr state)
1075{
1076 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001077 unsigned int maxAttrs;
1078 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001079
1080 if (state == NULL)
1081 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001082 if ((ctxt->freeState != NULL) &&
1083 (ctxt->freeState->nbState > 0)) {
1084 ctxt->freeState->nbState--;
1085 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1086 } else {
1087 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1088 if (ret == NULL) {
1089 if ((ctxt != NULL) && (ctxt->error != NULL))
1090 ctxt->error(ctxt->userData, "Out of memory\n");
1091 return (NULL);
1092 }
1093 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001094 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001095 attrs = ret->attrs;
1096 maxAttrs = ret->maxAttrs;
1097 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1098 ret->attrs = attrs;
1099 ret->maxAttrs = maxAttrs;
1100 if (state->nbAttrs > 0) {
1101 if (ret->attrs == NULL) {
1102 ret->maxAttrs = state->maxAttrs;
1103 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1104 sizeof(xmlAttrPtr));
1105 if (ret->attrs == NULL) {
1106 if ((ctxt != NULL) && (ctxt->error != NULL))
1107 ctxt->error(ctxt->userData, "Out of memory\n");
1108 ret->nbAttrs = 0;
1109 return (ret);
1110 }
1111 } else if (ret->maxAttrs < state->nbAttrs) {
1112 xmlAttrPtr *tmp;
1113
1114 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1115 sizeof(xmlAttrPtr));
1116 if (tmp == NULL) {
1117 if ((ctxt != NULL) && (ctxt->error != NULL))
1118 ctxt->error(ctxt->userData, "Out of memory\n");
1119 ret->nbAttrs = 0;
1120 return (ret);
1121 }
1122 ret->maxAttrs = state->maxAttrs;
1123 }
1124 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1125 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001126 return(ret);
1127}
1128
1129/**
1130 * xmlRelaxNGEqualValidState:
1131 * @ctxt: a Relax-NG validation context
1132 * @state1: a validation state
1133 * @state2: a validation state
1134 *
1135 * Compare the validation states for equality
1136 *
1137 * Returns 1 if equald, 0 otherwise
1138 */
1139static int
1140xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1141 xmlRelaxNGValidStatePtr state1,
1142 xmlRelaxNGValidStatePtr state2)
1143{
1144 int i;
1145
1146 if ((state1 == NULL) || (state2 == NULL))
1147 return(0);
1148 if (state1 == state2)
1149 return(1);
1150 if (state1->node != state2->node)
1151 return(0);
1152 if (state1->seq != state2->seq)
1153 return(0);
1154 if (state1->nbAttrLeft != state2->nbAttrLeft)
1155 return(0);
1156 if (state1->nbAttrs != state2->nbAttrs)
1157 return(0);
1158 if (state1->endvalue != state2->endvalue)
1159 return(0);
1160 if ((state1->value != state2->value) &&
1161 (!xmlStrEqual(state1->value, state2->value)))
1162 return(0);
1163 for (i = 0;i < state1->nbAttrs;i++) {
1164 if (state1->attrs[i] != state2->attrs[i])
1165 return(0);
1166 }
1167 return(1);
1168}
1169
1170/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001171 * xmlRelaxNGFreeValidState:
1172 * @state: a validation state structure
1173 *
1174 * Deallocate a RelaxNG validation state structure.
1175 */
1176static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001177xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1178 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001179{
1180 if (state == NULL)
1181 return;
1182
Daniel Veillard798024a2003-03-19 10:36:09 +00001183 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1184 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1185 }
1186 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1187 if (state->attrs != NULL)
1188 xmlFree(state->attrs);
1189 xmlFree(state);
1190 } else {
1191 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1192 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001193}
1194
1195/************************************************************************
1196 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001197 * Document functions *
1198 * *
1199 ************************************************************************/
1200static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1201 xmlDocPtr doc);
1202
1203/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001204 * xmlRelaxNGIncludePush:
1205 * @ctxt: the parser context
1206 * @value: the element doc
1207 *
1208 * Pushes a new include on top of the include stack
1209 *
1210 * Returns 0 in case of error, the index in the stack otherwise
1211 */
1212static int
1213xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1214 xmlRelaxNGIncludePtr value)
1215{
1216 if (ctxt->incTab == NULL) {
1217 ctxt->incMax = 4;
1218 ctxt->incNr = 0;
1219 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1220 ctxt->incMax * sizeof(ctxt->incTab[0]));
1221 if (ctxt->incTab == NULL) {
1222 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1223 return (0);
1224 }
1225 }
1226 if (ctxt->incNr >= ctxt->incMax) {
1227 ctxt->incMax *= 2;
1228 ctxt->incTab =
1229 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1230 ctxt->incMax *
1231 sizeof(ctxt->incTab[0]));
1232 if (ctxt->incTab == NULL) {
1233 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1234 return (0);
1235 }
1236 }
1237 ctxt->incTab[ctxt->incNr] = value;
1238 ctxt->inc = value;
1239 return (ctxt->incNr++);
1240}
1241
1242/**
1243 * xmlRelaxNGIncludePop:
1244 * @ctxt: the parser context
1245 *
1246 * Pops the top include from the include stack
1247 *
1248 * Returns the include just removed
1249 */
1250static xmlRelaxNGIncludePtr
1251xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1252{
1253 xmlRelaxNGIncludePtr ret;
1254
1255 if (ctxt->incNr <= 0)
1256 return (0);
1257 ctxt->incNr--;
1258 if (ctxt->incNr > 0)
1259 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1260 else
1261 ctxt->inc = NULL;
1262 ret = ctxt->incTab[ctxt->incNr];
1263 ctxt->incTab[ctxt->incNr] = 0;
1264 return (ret);
1265}
1266
1267/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001268 * xmlRelaxNGRemoveRedefine:
1269 * @ctxt: the parser context
1270 * @URL: the normalized URL
1271 * @target: the included target
1272 * @name: the define name to eliminate
1273 *
1274 * Applies the elimination algorithm of 4.7
1275 *
1276 * Returns 0 in case of error, 1 in case of success.
1277 */
1278static int
1279xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1280 const xmlChar *URL ATTRIBUTE_UNUSED,
1281 xmlNodePtr target, const xmlChar *name) {
1282 int found = 0;
1283 xmlNodePtr tmp, tmp2;
1284 xmlChar *name2;
1285
1286#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001287 if (name == NULL)
1288 xmlGenericError(xmlGenericErrorContext,
1289 "Elimination of <include> start from %s\n", URL);
1290 else
1291 xmlGenericError(xmlGenericErrorContext,
1292 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001293#endif
1294 tmp = target;
1295 while (tmp != NULL) {
1296 tmp2 = tmp->next;
1297 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1298 found = 1;
1299 xmlUnlinkNode(tmp);
1300 xmlFreeNode(tmp);
1301 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1302 name2 = xmlGetProp(tmp, BAD_CAST "name");
1303 xmlRelaxNGNormExtSpace(name2);
1304 if (name2 != NULL) {
1305 if (xmlStrEqual(name, name2)) {
1306 found = 1;
1307 xmlUnlinkNode(tmp);
1308 xmlFreeNode(tmp);
1309 }
1310 xmlFree(name2);
1311 }
1312 } else if (IS_RELAXNG(tmp, "include")) {
1313 xmlChar *href = NULL;
1314 xmlRelaxNGDocumentPtr inc = tmp->_private;
1315
1316 if ((inc != NULL) && (inc->doc != NULL) &&
1317 (inc->doc->children != NULL)) {
1318
1319 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1320#ifdef DEBUG_INCLUDE
1321 href = xmlGetProp(tmp, BAD_CAST "href");
1322#endif
1323 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1324 inc->doc->children->children, name) == 1) {
1325 found = 1;
1326 }
1327 if (href != NULL)
1328 xmlFree(href);
1329 }
1330 }
1331 }
1332 tmp = tmp2;
1333 }
1334 return(found);
1335}
1336
1337/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001338 * xmlRelaxNGLoadInclude:
1339 * @ctxt: the parser context
1340 * @URL: the normalized URL
1341 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001342 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001343 *
1344 * First lookup if the document is already loaded into the parser context,
1345 * check against recursion. If not found the resource is loaded and
1346 * the content is preprocessed before being returned back to the caller.
1347 *
1348 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1349 */
1350static xmlRelaxNGIncludePtr
1351xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001352 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001353 xmlRelaxNGIncludePtr ret = NULL;
1354 xmlDocPtr doc;
1355 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001356 xmlNodePtr root, cur;
1357
1358#ifdef DEBUG_INCLUDE
1359 xmlGenericError(xmlGenericErrorContext,
1360 "xmlRelaxNGLoadInclude(%s)\n", URL);
1361#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001362
1363 /*
1364 * check against recursion in the stack
1365 */
1366 for (i = 0;i < ctxt->incNr;i++) {
1367 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1368 if (ctxt->error != NULL)
1369 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001370 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001371 URL);
1372 ctxt->nbErrors++;
1373 return(NULL);
1374 }
1375 }
1376
1377 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001378 * load the document
1379 */
1380 doc = xmlParseFile((const char *) URL);
1381 if (doc == NULL) {
1382 if (ctxt->error != NULL)
1383 ctxt->error(ctxt->userData,
1384 "xmlRelaxNG: could not load %s\n", URL);
1385 ctxt->nbErrors++;
1386 return (NULL);
1387 }
1388
Daniel Veillard5add8682003-03-10 13:13:58 +00001389#ifdef DEBUG_INCLUDE
1390 xmlGenericError(xmlGenericErrorContext,
1391 "Parsed %s Okay\n", URL);
1392#endif
1393
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001394 /*
1395 * Allocate the document structures and register it first.
1396 */
1397 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1398 if (ret == NULL) {
1399 if (ctxt->error != NULL)
1400 ctxt->error(ctxt->userData,
1401 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1402 ctxt->nbErrors++;
1403 xmlFreeDoc(doc);
1404 return (NULL);
1405 }
1406 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1407 ret->doc = doc;
1408 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001409 ret->next = ctxt->includes;
1410 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001411
1412 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001413 * transmit the ns if needed
1414 */
1415 if (ns != NULL) {
1416 root = xmlDocGetRootElement(doc);
1417 if (root != NULL) {
1418 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1419 xmlSetProp(root, BAD_CAST"ns", ns);
1420 }
1421 }
1422 }
1423
1424 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001425 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001426 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 xmlRelaxNGIncludePush(ctxt, ret);
1428
1429 /*
1430 * Some preprocessing of the document content, this include recursing
1431 * in the include stack.
1432 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001433#ifdef DEBUG_INCLUDE
1434 xmlGenericError(xmlGenericErrorContext,
1435 "cleanup of %s\n", URL);
1436#endif
1437
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001438 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1439 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001440 ctxt->inc = NULL;
1441 return(NULL);
1442 }
1443
1444 /*
1445 * Pop up the include from the stack
1446 */
1447 xmlRelaxNGIncludePop(ctxt);
1448
Daniel Veillard5add8682003-03-10 13:13:58 +00001449#ifdef DEBUG_INCLUDE
1450 xmlGenericError(xmlGenericErrorContext,
1451 "Checking of %s\n", URL);
1452#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001453 /*
1454 * Check that the top element is a grammar
1455 */
1456 root = xmlDocGetRootElement(doc);
1457 if (root == NULL) {
1458 if (ctxt->error != NULL)
1459 ctxt->error(ctxt->userData,
1460 "xmlRelaxNG: included document is empty %s\n", URL);
1461 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001462 return (NULL);
1463 }
1464 if (!IS_RELAXNG(root, "grammar")) {
1465 if (ctxt->error != NULL)
1466 ctxt->error(ctxt->userData,
1467 "xmlRelaxNG: included document %s root is not a grammar\n",
1468 URL);
1469 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001470 return (NULL);
1471 }
1472
1473 /*
1474 * Elimination of redefined rules in the include.
1475 */
1476 cur = node->children;
1477 while (cur != NULL) {
1478 if (IS_RELAXNG(cur, "start")) {
1479 int found = 0;
1480
Daniel Veillard5add8682003-03-10 13:13:58 +00001481 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001482 if (!found) {
1483 if (ctxt->error != NULL)
1484 ctxt->error(ctxt->userData,
1485 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1486 URL);
1487 ctxt->nbErrors++;
1488 }
1489 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001490 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001491
1492 name = xmlGetProp(cur, BAD_CAST "name");
1493 if (name == NULL) {
1494 if (ctxt->error != NULL)
1495 ctxt->error(ctxt->userData,
1496 "xmlRelaxNG: include %s has define without name\n",
1497 URL);
1498 ctxt->nbErrors++;
1499 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001500 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001501
Daniel Veillardd2298792003-02-14 16:54:11 +00001502 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001503 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1504 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001505 if (!found) {
1506 if (ctxt->error != NULL)
1507 ctxt->error(ctxt->userData,
1508 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1509 URL, name);
1510 ctxt->nbErrors++;
1511 }
1512 xmlFree(name);
1513 }
1514 }
1515 cur = cur->next;
1516 }
1517
1518
1519 return(ret);
1520}
1521
1522/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001523 * xmlRelaxNGValidErrorPush:
1524 * @ctxt: the validation context
1525 * @err: the error code
1526 * @arg1: the first string argument
1527 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001528 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001529 *
1530 * Pushes a new error on top of the error stack
1531 *
1532 * Returns 0 in case of error, the index in the stack otherwise
1533 */
1534static int
1535xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001536 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001537{
1538 xmlRelaxNGValidErrorPtr cur;
1539 if (ctxt->errTab == NULL) {
1540 ctxt->errMax = 8;
1541 ctxt->errNr = 0;
1542 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1543 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1544 if (ctxt->errTab == NULL) {
1545 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1546 return (0);
1547 }
Daniel Veillard20863822003-03-22 17:51:47 +00001548 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001549 }
1550 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001551 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001552 ctxt->errTab =
1553 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001554 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001555 if (ctxt->errTab == NULL) {
1556 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1557 return (0);
1558 }
Daniel Veillard20863822003-03-22 17:51:47 +00001559 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001560 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001561 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001562 (ctxt->err->node == ctxt->state->node) &&
1563 (ctxt->err->err == err))
1564 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001565 cur = &ctxt->errTab[ctxt->errNr];
1566 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001567 if (dup) {
1568 cur->arg1 = xmlStrdup(arg1);
1569 cur->arg2 = xmlStrdup(arg2);
1570 cur->flags = ERROR_IS_DUP;
1571 } else {
1572 cur->arg1 = arg1;
1573 cur->arg2 = arg2;
1574 cur->flags = 0;
1575 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001576 if (ctxt->state != NULL) {
1577 cur->node = ctxt->state->node;
1578 cur->seq = ctxt->state->seq;
1579 } else {
1580 cur->node = NULL;
1581 cur->seq = NULL;
1582 }
1583 ctxt->err = cur;
1584 return (ctxt->errNr++);
1585}
1586
1587/**
1588 * xmlRelaxNGValidErrorPop:
1589 * @ctxt: the validation context
1590 *
1591 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001592 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001593static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001594xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1595{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001596 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001597
Daniel Veillard580ced82003-03-21 21:22:48 +00001598 if (ctxt->errNr <= 0) {
1599 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001600 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001601 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001602 ctxt->errNr--;
1603 if (ctxt->errNr > 0)
1604 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1605 else
1606 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001607 cur = &ctxt->errTab[ctxt->errNr];
1608 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001609 if (cur->arg1 != NULL)
1610 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001611 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001612 if (cur->arg2 != NULL)
1613 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001614 cur->arg2 = NULL;
1615 cur->flags = 0;
1616 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001617}
1618
Daniel Veillard42f12e92003-03-07 18:32:59 +00001619/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001620 * xmlRelaxNGDocumentPush:
1621 * @ctxt: the parser context
1622 * @value: the element doc
1623 *
1624 * Pushes a new doc on top of the doc stack
1625 *
1626 * Returns 0 in case of error, the index in the stack otherwise
1627 */
1628static int
1629xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1630 xmlRelaxNGDocumentPtr value)
1631{
1632 if (ctxt->docTab == NULL) {
1633 ctxt->docMax = 4;
1634 ctxt->docNr = 0;
1635 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1636 ctxt->docMax * sizeof(ctxt->docTab[0]));
1637 if (ctxt->docTab == NULL) {
1638 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1639 return (0);
1640 }
1641 }
1642 if (ctxt->docNr >= ctxt->docMax) {
1643 ctxt->docMax *= 2;
1644 ctxt->docTab =
1645 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1646 ctxt->docMax *
1647 sizeof(ctxt->docTab[0]));
1648 if (ctxt->docTab == NULL) {
1649 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1650 return (0);
1651 }
1652 }
1653 ctxt->docTab[ctxt->docNr] = value;
1654 ctxt->doc = value;
1655 return (ctxt->docNr++);
1656}
1657
1658/**
1659 * xmlRelaxNGDocumentPop:
1660 * @ctxt: the parser context
1661 *
1662 * Pops the top doc from the doc stack
1663 *
1664 * Returns the doc just removed
1665 */
1666static xmlRelaxNGDocumentPtr
1667xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1668{
1669 xmlRelaxNGDocumentPtr ret;
1670
1671 if (ctxt->docNr <= 0)
1672 return (0);
1673 ctxt->docNr--;
1674 if (ctxt->docNr > 0)
1675 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1676 else
1677 ctxt->doc = NULL;
1678 ret = ctxt->docTab[ctxt->docNr];
1679 ctxt->docTab[ctxt->docNr] = 0;
1680 return (ret);
1681}
1682
1683/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001684 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001685 * @ctxt: the parser context
1686 * @URL: the normalized URL
1687 * @ns: the inherited ns if any
1688 *
1689 * First lookup if the document is already loaded into the parser context,
1690 * check against recursion. If not found the resource is loaded and
1691 * the content is preprocessed before being returned back to the caller.
1692 *
1693 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1694 */
1695static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001696xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001697 const xmlChar *ns) {
1698 xmlRelaxNGDocumentPtr ret = NULL;
1699 xmlDocPtr doc;
1700 xmlNodePtr root;
1701 int i;
1702
1703 /*
1704 * check against recursion in the stack
1705 */
1706 for (i = 0;i < ctxt->docNr;i++) {
1707 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1708 if (ctxt->error != NULL)
1709 ctxt->error(ctxt->userData,
1710 "Detected an externalRef recursion for %s\n",
1711 URL);
1712 ctxt->nbErrors++;
1713 return(NULL);
1714 }
1715 }
1716
1717 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001718 * load the document
1719 */
1720 doc = xmlParseFile((const char *) URL);
1721 if (doc == NULL) {
1722 if (ctxt->error != NULL)
1723 ctxt->error(ctxt->userData,
1724 "xmlRelaxNG: could not load %s\n", URL);
1725 ctxt->nbErrors++;
1726 return (NULL);
1727 }
1728
1729 /*
1730 * Allocate the document structures and register it first.
1731 */
1732 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1733 if (ret == NULL) {
1734 if (ctxt->error != NULL)
1735 ctxt->error(ctxt->userData,
1736 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1737 ctxt->nbErrors++;
1738 xmlFreeDoc(doc);
1739 return (NULL);
1740 }
1741 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1742 ret->doc = doc;
1743 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001744 ret->next = ctxt->documents;
1745 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001746
1747 /*
1748 * transmit the ns if needed
1749 */
1750 if (ns != NULL) {
1751 root = xmlDocGetRootElement(doc);
1752 if (root != NULL) {
1753 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1754 xmlSetProp(root, BAD_CAST"ns", ns);
1755 }
1756 }
1757 }
1758
1759 /*
1760 * push it on the stack and register it in the hash table
1761 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001762 xmlRelaxNGDocumentPush(ctxt, ret);
1763
1764 /*
1765 * Some preprocessing of the document content
1766 */
1767 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1768 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001769 ctxt->doc = NULL;
1770 return(NULL);
1771 }
1772
1773 xmlRelaxNGDocumentPop(ctxt);
1774
1775 return(ret);
1776}
1777
1778/************************************************************************
1779 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001780 * Error functions *
1781 * *
1782 ************************************************************************/
1783
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001784#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1785#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1786#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1787#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1788#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001789
Daniel Veillardfd573f12003-03-16 17:52:32 +00001790#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001791static const char *
1792xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1793 if (def == NULL)
1794 return("none");
1795 switch(def->type) {
1796 case XML_RELAXNG_EMPTY: return("empty");
1797 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1798 case XML_RELAXNG_EXCEPT: return("except");
1799 case XML_RELAXNG_TEXT: return("text");
1800 case XML_RELAXNG_ELEMENT: return("element");
1801 case XML_RELAXNG_DATATYPE: return("datatype");
1802 case XML_RELAXNG_VALUE: return("value");
1803 case XML_RELAXNG_LIST: return("list");
1804 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1805 case XML_RELAXNG_DEF: return("def");
1806 case XML_RELAXNG_REF: return("ref");
1807 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1808 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001809 case XML_RELAXNG_OPTIONAL: return("optional");
1810 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001811 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1812 case XML_RELAXNG_CHOICE: return("choice");
1813 case XML_RELAXNG_GROUP: return("group");
1814 case XML_RELAXNG_INTERLEAVE: return("interleave");
1815 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001816 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001817 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001818 }
1819 return("unknown");
1820}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001821#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001822
Daniel Veillard6eadf632003-01-23 18:29:16 +00001823/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001824 * xmlRelaxNGGetErrorString:
1825 * @err: the error code
1826 * @arg1: the first string argument
1827 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001828 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001829 * computes a formatted error string for the given error code and args
1830 *
1831 * Returns the error string, it must be deallocated by the caller
1832 */
1833static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001834xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1835 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001836 char msg[1000];
1837
1838 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001839 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001840 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001841 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001842
1843 msg[0] = 0;
1844 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001845 case XML_RELAXNG_OK:
1846 return(NULL);
1847 case XML_RELAXNG_ERR_MEMORY:
1848 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001849 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001850 snprintf(msg, 1000, "failed to validate type %s", arg1);
1851 break;
1852 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001853 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001854 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001855 case XML_RELAXNG_ERR_DUPID:
1856 snprintf(msg, 1000, "ID %s redefined", arg1);
1857 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001858 case XML_RELAXNG_ERR_TYPECMP:
1859 snprintf(msg, 1000, "failed to compare type %s", arg1);
1860 break;
1861 case XML_RELAXNG_ERR_NOSTATE:
1862 return(xmlCharStrdup("Internal error: no state"));
1863 case XML_RELAXNG_ERR_NODEFINE:
1864 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001865 case XML_RELAXNG_ERR_INTERNAL:
1866 snprintf(msg, 1000, "Internal error: %s", arg1);
1867 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001868 case XML_RELAXNG_ERR_LISTEXTRA:
1869 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1870 break;
1871 case XML_RELAXNG_ERR_INTERNODATA:
1872 return(xmlCharStrdup("Internal: interleave block has no data"));
1873 case XML_RELAXNG_ERR_INTERSEQ:
1874 return(xmlCharStrdup("Invalid sequence in interleave"));
1875 case XML_RELAXNG_ERR_INTEREXTRA:
1876 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1877 break;
1878 case XML_RELAXNG_ERR_ELEMNAME:
1879 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1880 break;
1881 case XML_RELAXNG_ERR_ELEMNONS:
1882 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1883 break;
1884 case XML_RELAXNG_ERR_ELEMWRONGNS:
1885 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1886 arg1, arg2);
1887 break;
1888 case XML_RELAXNG_ERR_ELEMEXTRANS:
1889 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1890 break;
1891 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1892 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1893 break;
1894 case XML_RELAXNG_ERR_NOELEM:
1895 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1896 break;
1897 case XML_RELAXNG_ERR_NOTELEM:
1898 return(xmlCharStrdup("Expecting an element got text"));
1899 case XML_RELAXNG_ERR_ATTRVALID:
1900 snprintf(msg, 1000, "Element %s failed to validate attributes",
1901 arg1);
1902 break;
1903 case XML_RELAXNG_ERR_CONTENTVALID:
1904 snprintf(msg, 1000, "Element %s failed to validate content",
1905 arg1);
1906 break;
1907 case XML_RELAXNG_ERR_EXTRACONTENT:
1908 snprintf(msg, 1000, "Element %s has extra content: %s",
1909 arg1, arg2);
1910 break;
1911 case XML_RELAXNG_ERR_INVALIDATTR:
1912 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1913 arg1, arg2);
1914 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001915 case XML_RELAXNG_ERR_LACKDATA:
1916 snprintf(msg, 1000, "Datatype element %s contains no data",
1917 arg1);
1918 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001919 case XML_RELAXNG_ERR_DATAELEM:
1920 snprintf(msg, 1000, "Datatype element %s has child elements",
1921 arg1);
1922 break;
1923 case XML_RELAXNG_ERR_VALELEM:
1924 snprintf(msg, 1000, "Value element %s has child elements",
1925 arg1);
1926 break;
1927 case XML_RELAXNG_ERR_LISTELEM:
1928 snprintf(msg, 1000, "List element %s has child elements",
1929 arg1);
1930 break;
1931 case XML_RELAXNG_ERR_DATATYPE:
1932 snprintf(msg, 1000, "Error validating datatype %s",
1933 arg1);
1934 break;
1935 case XML_RELAXNG_ERR_VALUE:
1936 snprintf(msg, 1000, "Error validating value %s",
1937 arg1);
1938 break;
1939 case XML_RELAXNG_ERR_LIST:
1940 return(xmlCharStrdup("Error validating list"));
1941 case XML_RELAXNG_ERR_NOGRAMMAR:
1942 return(xmlCharStrdup("No top grammar defined"));
1943 case XML_RELAXNG_ERR_EXTRADATA:
1944 return(xmlCharStrdup("Extra data in the document"));
1945 default:
1946 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001947 }
1948 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001949 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001950 }
1951 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001952 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001953}
1954
1955/**
1956 * xmlRelaxNGValidErrorContext:
1957 * @ctxt: the validation context
1958 * @node: the node
1959 * @child: the node child generating the problem.
1960 *
1961 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001962 */
1963static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001964xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1965 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001966{
1967 int line = 0;
1968 const xmlChar *file = NULL;
1969 const xmlChar *name = NULL;
1970 const char *type = "error";
1971
1972 if ((ctxt == NULL) || (ctxt->error == NULL))
1973 return;
1974
1975 if (child != NULL)
1976 node = child;
1977
1978 if (node != NULL) {
1979 if ((node->type == XML_DOCUMENT_NODE) ||
1980 (node->type == XML_HTML_DOCUMENT_NODE)) {
1981 xmlDocPtr doc = (xmlDocPtr) node;
1982
1983 file = doc->URL;
1984 } else {
1985 /*
1986 * Try to find contextual informations to report
1987 */
1988 if (node->type == XML_ELEMENT_NODE) {
1989 line = (int) node->content;
1990 } else if ((node->prev != NULL) &&
1991 (node->prev->type == XML_ELEMENT_NODE)) {
1992 line = (int) node->prev->content;
1993 } else if ((node->parent != NULL) &&
1994 (node->parent->type == XML_ELEMENT_NODE)) {
1995 line = (int) node->parent->content;
1996 }
1997 if ((node->doc != NULL) && (node->doc->URL != NULL))
1998 file = node->doc->URL;
1999 if (node->name != NULL)
2000 name = node->name;
2001 }
2002 }
2003
Daniel Veillard42f12e92003-03-07 18:32:59 +00002004 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002005
2006 if ((file != NULL) && (line != 0) && (name != NULL))
2007 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2008 type, file, line, name);
2009 else if ((file != NULL) && (name != NULL))
2010 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2011 type, file, name);
2012 else if ((file != NULL) && (line != 0))
2013 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2014 else if (file != NULL)
2015 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2016 else if (name != NULL)
2017 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2018 else
2019 ctxt->error(ctxt->userData, "%s\n", type);
2020}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002021
2022/**
2023 * xmlRelaxNGShowValidError:
2024 * @ctxt: the validation context
2025 * @err: the error number
2026 * @node: the node
2027 * @child: the node child generating the problem.
2028 * @arg1: the first argument
2029 * @arg2: the second argument
2030 *
2031 * Show a validation error.
2032 */
2033static void
2034xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2035 xmlNodePtr node, xmlNodePtr child,
2036 const xmlChar *arg1, const xmlChar *arg2)
2037{
2038 xmlChar *msg;
2039
2040 if (ctxt->error == NULL)
2041 return;
2042
2043 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2044 if (msg == NULL)
2045 return;
2046
2047 xmlRelaxNGValidErrorContext(ctxt, node, child);
2048 ctxt->error(ctxt->userData, "%s\n", msg);
2049 xmlFree(msg);
2050}
2051
2052/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002053 * xmlRelaxNGPopErrors:
2054 * @ctxt: the validation context
2055 * @level: the error level in the stack
2056 *
2057 * pop and discard all errors until the given level is reached
2058 */
2059static void
2060xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2061 int i;
2062 xmlRelaxNGValidErrorPtr err;
2063
2064 for (i = level;i < ctxt->errNr;i++) {
2065 err = &ctxt->errTab[i];
2066 if (err->flags & ERROR_IS_DUP) {
2067 if (err->arg1 != NULL)
2068 xmlFree((xmlChar *)err->arg1);
2069 err->arg1 = NULL;
2070 if (err->arg2 != NULL)
2071 xmlFree((xmlChar *)err->arg2);
2072 err->arg2 = NULL;
2073 err->flags = 0;
2074 }
2075 }
2076 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002077 if (ctxt->errNr <= 0)
2078 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002079}
2080/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002081 * xmlRelaxNGDumpValidError:
2082 * @ctxt: the validation context
2083 *
2084 * Show all validation error over a given index.
2085 */
2086static void
2087xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002088 int i, j;
2089 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002090
2091 for (i = 0;i < ctxt->errNr;i++) {
2092 err = &ctxt->errTab[i];
Daniel Veillard580ced82003-03-21 21:22:48 +00002093 for (j = 0;j < i;j++) {
2094 dup = &ctxt->errTab[j];
2095 if ((err->err == dup->err) && (err->node == dup->node) &&
2096 (xmlStrEqual(err->arg1, dup->arg1)) &&
2097 (xmlStrEqual(err->arg2, dup->arg2))) {
2098 goto skip;
2099 }
2100 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002101 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2102 err->arg1, err->arg2);
Daniel Veillard580ced82003-03-21 21:22:48 +00002103skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002104 if (err->flags & ERROR_IS_DUP) {
2105 if (err->arg1 != NULL)
2106 xmlFree((xmlChar *)err->arg1);
2107 err->arg1 = NULL;
2108 if (err->arg2 != NULL)
2109 xmlFree((xmlChar *)err->arg2);
2110 err->arg2 = NULL;
2111 err->flags = 0;
2112 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002113 }
2114 ctxt->errNr = 0;
2115}
2116/**
2117 * xmlRelaxNGAddValidError:
2118 * @ctxt: the validation context
2119 * @err: the error number
2120 * @arg1: the first argument
2121 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002122 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002123 *
2124 * Register a validation error, either generating it if it's sure
2125 * or stacking it for later handling if unsure.
2126 */
2127static void
2128xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002129 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002130{
2131 if ((ctxt == NULL) || (ctxt->error == NULL))
2132 return;
2133
2134 /*
2135 * generate the error directly
2136 */
2137 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2138 xmlNodePtr node, seq;
2139 /*
2140 * Flush first any stacked error which might be the
2141 * real cause of the problem.
2142 */
2143 if (ctxt->errNr != 0)
2144 xmlRelaxNGDumpValidError(ctxt);
2145 if (ctxt->state != NULL) {
2146 node = ctxt->state->node;
2147 seq = ctxt->state->seq;
2148 } else {
2149 node = seq = NULL;
2150 }
2151 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2152 }
2153 /*
2154 * Stack the error for later processing if needed
2155 */
2156 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002157 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002158 }
2159}
2160
Daniel Veillard6eadf632003-01-23 18:29:16 +00002161
2162/************************************************************************
2163 * *
2164 * Type library hooks *
2165 * *
2166 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002167static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2168 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002169
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002170/**
2171 * xmlRelaxNGSchemaTypeHave:
2172 * @data: data needed for the library
2173 * @type: the type name
2174 *
2175 * Check if the given type is provided by
2176 * the W3C XMLSchema Datatype library.
2177 *
2178 * Returns 1 if yes, 0 if no and -1 in case of error.
2179 */
2180static int
2181xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002182 const xmlChar *type) {
2183 xmlSchemaTypePtr typ;
2184
2185 if (type == NULL)
2186 return(-1);
2187 typ = xmlSchemaGetPredefinedType(type,
2188 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2189 if (typ == NULL)
2190 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002191 return(1);
2192}
2193
2194/**
2195 * xmlRelaxNGSchemaTypeCheck:
2196 * @data: data needed for the library
2197 * @type: the type name
2198 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002199 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002200 *
2201 * Check if the given type and value are validated by
2202 * the W3C XMLSchema Datatype library.
2203 *
2204 * Returns 1 if yes, 0 if no and -1 in case of error.
2205 */
2206static int
2207xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002208 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002209 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002210 void **result,
2211 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002212 xmlSchemaTypePtr typ;
2213 int ret;
2214
2215 /*
2216 * TODO: the type should be cached ab provided back, interface subject
2217 * to changes.
2218 * TODO: handle facets, may require an additional interface and keep
2219 * the value returned from the validation.
2220 */
2221 if ((type == NULL) || (value == NULL))
2222 return(-1);
2223 typ = xmlSchemaGetPredefinedType(type,
2224 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2225 if (typ == NULL)
2226 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002227 ret = xmlSchemaValPredefTypeNode(typ, value,
2228 (xmlSchemaValPtr *) result, node);
2229 if (ret == 2) /* special ID error code */
2230 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002231 if (ret == 0)
2232 return(1);
2233 if (ret > 0)
2234 return(0);
2235 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002236}
2237
2238/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002239 * xmlRelaxNGSchemaFacetCheck:
2240 * @data: data needed for the library
2241 * @type: the type name
2242 * @facet: the facet name
2243 * @val: the facet value
2244 * @strval: the string value
2245 * @value: the value to check
2246 *
2247 * Function provided by a type library to check a value facet
2248 *
2249 * Returns 1 if yes, 0 if no and -1 in case of error.
2250 */
2251static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002252xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002253 const xmlChar *facetname, const xmlChar *val,
2254 const xmlChar *strval, void *value) {
2255 xmlSchemaFacetPtr facet;
2256 xmlSchemaTypePtr typ;
2257 int ret;
2258
2259 if ((type == NULL) || (strval == NULL))
2260 return(-1);
2261 typ = xmlSchemaGetPredefinedType(type,
2262 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2263 if (typ == NULL)
2264 return(-1);
2265
2266 facet = xmlSchemaNewFacet();
2267 if (facet == NULL)
2268 return(-1);
2269
2270 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2271 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2272 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2273 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2274 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2275 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2276 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2277 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2278 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2279 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2280 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2281 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2282 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2283 facet->type = XML_SCHEMA_FACET_PATTERN;
2284 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2285 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2286 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2287 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2288 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2289 facet->type = XML_SCHEMA_FACET_LENGTH;
2290 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2291 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2292 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2293 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2294 } else {
2295 xmlSchemaFreeFacet(facet);
2296 return(-1);
2297 }
2298 facet->value = xmlStrdup(val);
2299 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2300 if (ret != 0) {
2301 xmlSchemaFreeFacet(facet);
2302 return(-1);
2303 }
2304 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2305 xmlSchemaFreeFacet(facet);
2306 if (ret != 0)
2307 return(-1);
2308 return(0);
2309}
2310
2311/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002312 * xmlRelaxNGSchemaFreeValue:
2313 * @data: data needed for the library
2314 * @value: the value to free
2315 *
2316 * Function provided by a type library to free a Schemas value
2317 *
2318 * Returns 1 if yes, 0 if no and -1 in case of error.
2319 */
2320static void
2321xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2322 xmlSchemaFreeValue(value);
2323}
2324
2325/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002326 * xmlRelaxNGSchemaTypeCompare:
2327 * @data: data needed for the library
2328 * @type: the type name
2329 * @value1: the first value
2330 * @value2: the second value
2331 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002332 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002333 * Datatype library.
2334 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002335 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002336 */
2337static int
2338xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2339 const xmlChar *type ATTRIBUTE_UNUSED,
2340 const xmlChar *value1 ATTRIBUTE_UNUSED,
2341 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002342 int ret;
2343 xmlSchemaTypePtr typ;
2344 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2345
2346 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2347 return(-1);
2348 typ = xmlSchemaGetPredefinedType(type,
2349 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2350 if (typ == NULL)
2351 return(-1);
2352 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, NULL);
2353 if (ret != 0)
2354 return(-1);
2355 if (res1 == NULL)
2356 return(-1);
2357 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, NULL);
2358 if (ret != 0) {
2359 xmlSchemaFreeValue(res1);
2360 return(-1);
2361 }
2362 if (res1 == NULL) {
2363 xmlSchemaFreeValue(res1);
2364 return(-1);
2365 }
2366 ret = xmlSchemaCompareValues(res1, res2);
2367 xmlSchemaFreeValue(res1);
2368 xmlSchemaFreeValue(res2);
2369 if (ret == -2)
2370 return(-1);
2371 if (ret == 0)
2372 return(1);
2373 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002374}
2375
2376/**
2377 * xmlRelaxNGDefaultTypeHave:
2378 * @data: data needed for the library
2379 * @type: the type name
2380 *
2381 * Check if the given type is provided by
2382 * the default datatype library.
2383 *
2384 * Returns 1 if yes, 0 if no and -1 in case of error.
2385 */
2386static int
2387xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2388 if (type == NULL)
2389 return(-1);
2390 if (xmlStrEqual(type, BAD_CAST "string"))
2391 return(1);
2392 if (xmlStrEqual(type, BAD_CAST "token"))
2393 return(1);
2394 return(0);
2395}
2396
2397/**
2398 * xmlRelaxNGDefaultTypeCheck:
2399 * @data: data needed for the library
2400 * @type: the type name
2401 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002402 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002403 *
2404 * Check if the given type and value are validated by
2405 * the default datatype library.
2406 *
2407 * Returns 1 if yes, 0 if no and -1 in case of error.
2408 */
2409static int
2410xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2411 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002412 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002413 void **result ATTRIBUTE_UNUSED,
2414 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002415 if (value == NULL)
2416 return(-1);
2417 if (xmlStrEqual(type, BAD_CAST "string"))
2418 return(1);
2419 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002420 return(1);
2421 }
2422
2423 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002424}
2425
2426/**
2427 * xmlRelaxNGDefaultTypeCompare:
2428 * @data: data needed for the library
2429 * @type: the type name
2430 * @value1: the first value
2431 * @value2: the second value
2432 *
2433 * Compare two values accordingly a type from the default
2434 * datatype library.
2435 *
2436 * Returns 1 if yes, 0 if no and -1 in case of error.
2437 */
2438static int
2439xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2440 const xmlChar *type ATTRIBUTE_UNUSED,
2441 const xmlChar *value1 ATTRIBUTE_UNUSED,
2442 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002443 int ret = -1;
2444
2445 if (xmlStrEqual(type, BAD_CAST "string")) {
2446 ret = xmlStrEqual(value1, value2);
2447 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2448 if (!xmlStrEqual(value1, value2)) {
2449 xmlChar *nval, *nvalue;
2450
2451 /*
2452 * TODO: trivial optimizations are possible by
2453 * computing at compile-time
2454 */
2455 nval = xmlRelaxNGNormalize(NULL, value1);
2456 nvalue = xmlRelaxNGNormalize(NULL, value2);
2457
Daniel Veillardd4310742003-02-18 21:12:46 +00002458 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002459 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002460 else if (xmlStrEqual(nval, nvalue))
2461 ret = 1;
2462 else
2463 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002464 if (nval != NULL)
2465 xmlFree(nval);
2466 if (nvalue != NULL)
2467 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002468 } else
2469 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002470 }
2471 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002472}
2473
2474static int xmlRelaxNGTypeInitialized = 0;
2475static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2476
2477/**
2478 * xmlRelaxNGFreeTypeLibrary:
2479 * @lib: the type library structure
2480 * @namespace: the URI bound to the library
2481 *
2482 * Free the structure associated to the type library
2483 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002484static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002485xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2486 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2487 if (lib == NULL)
2488 return;
2489 if (lib->namespace != NULL)
2490 xmlFree((xmlChar *)lib->namespace);
2491 xmlFree(lib);
2492}
2493
2494/**
2495 * xmlRelaxNGRegisterTypeLibrary:
2496 * @namespace: the URI bound to the library
2497 * @data: data associated to the library
2498 * @have: the provide function
2499 * @check: the checking function
2500 * @comp: the comparison function
2501 *
2502 * Register a new type library
2503 *
2504 * Returns 0 in case of success and -1 in case of error.
2505 */
2506static int
2507xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2508 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002509 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2510 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002511 xmlRelaxNGTypeLibraryPtr lib;
2512 int ret;
2513
2514 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2515 (check == NULL) || (comp == NULL))
2516 return(-1);
2517 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2518 xmlGenericError(xmlGenericErrorContext,
2519 "Relax-NG types library '%s' already registered\n",
2520 namespace);
2521 return(-1);
2522 }
2523 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2524 if (lib == NULL) {
2525 xmlGenericError(xmlGenericErrorContext,
2526 "Relax-NG types library '%s' malloc() failed\n",
2527 namespace);
2528 return (-1);
2529 }
2530 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2531 lib->namespace = xmlStrdup(namespace);
2532 lib->data = data;
2533 lib->have = have;
2534 lib->comp = comp;
2535 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002536 lib->facet = facet;
2537 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002538 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2539 if (ret < 0) {
2540 xmlGenericError(xmlGenericErrorContext,
2541 "Relax-NG types library failed to register '%s'\n",
2542 namespace);
2543 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2544 return(-1);
2545 }
2546 return(0);
2547}
2548
2549/**
2550 * xmlRelaxNGInitTypes:
2551 *
2552 * Initilize the default type libraries.
2553 *
2554 * Returns 0 in case of success and -1 in case of error.
2555 */
2556static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002557xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002558 if (xmlRelaxNGTypeInitialized != 0)
2559 return(0);
2560 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2561 if (xmlRelaxNGRegisteredTypes == NULL) {
2562 xmlGenericError(xmlGenericErrorContext,
2563 "Failed to allocate sh table for Relax-NG types\n");
2564 return(-1);
2565 }
2566 xmlRelaxNGRegisterTypeLibrary(
2567 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2568 NULL,
2569 xmlRelaxNGSchemaTypeHave,
2570 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002571 xmlRelaxNGSchemaTypeCompare,
2572 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002573 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002574 xmlRelaxNGRegisterTypeLibrary(
2575 xmlRelaxNGNs,
2576 NULL,
2577 xmlRelaxNGDefaultTypeHave,
2578 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002579 xmlRelaxNGDefaultTypeCompare,
2580 NULL,
2581 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002582 xmlRelaxNGTypeInitialized = 1;
2583 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002584}
2585
2586/**
2587 * xmlRelaxNGCleanupTypes:
2588 *
2589 * Cleanup the default Schemas type library associated to RelaxNG
2590 */
2591void
2592xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002593 if (xmlRelaxNGTypeInitialized == 0)
2594 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002595 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002596 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2597 xmlRelaxNGFreeTypeLibrary);
2598 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002599}
2600
2601/************************************************************************
2602 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002603 * Compiling element content into regexp *
2604 * *
2605 * Sometime the element content can be compiled into a pure regexp, *
2606 * This allows a faster execution and streamability at that level *
2607 * *
2608 ************************************************************************/
2609
2610/**
2611 * xmlRelaxNGIsCompileable:
2612 * @define: the definition to check
2613 *
2614 * Check if a definition is nullable.
2615 *
2616 * Returns 1 if yes, 0 if no and -1 in case of error
2617 */
2618static int
2619xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2620 if (def == NULL) {
2621 return(-1);
2622 }
2623 switch(def->type) {
2624 case XML_RELAXNG_REF:
2625 case XML_RELAXNG_EXTERNALREF:
2626 case XML_RELAXNG_PARENTREF:
2627 case XML_RELAXNG_NOOP:
2628 case XML_RELAXNG_START:
2629 return(xmlRelaxNGIsCompileable(def->content));
2630 case XML_RELAXNG_TEXT:
2631 case XML_RELAXNG_DATATYPE:
2632 case XML_RELAXNG_LIST:
2633 case XML_RELAXNG_PARAM:
2634 case XML_RELAXNG_VALUE:
2635
2636 case XML_RELAXNG_EMPTY:
2637 case XML_RELAXNG_ELEMENT:
2638 return(1);
2639 case XML_RELAXNG_OPTIONAL:
2640 case XML_RELAXNG_ZEROORMORE:
2641 case XML_RELAXNG_ONEORMORE:
2642 case XML_RELAXNG_CHOICE:
2643 case XML_RELAXNG_GROUP:
2644 case XML_RELAXNG_DEF: {
2645 xmlRelaxNGDefinePtr list;
2646 int ret;
2647
2648 list = def->content;
2649 while (list != NULL) {
2650 ret = xmlRelaxNGIsCompileable(list);
2651 if (ret != 1)
2652 return(ret);
2653 list = list->next;
2654 }
2655 return(1);
2656 }
2657 case XML_RELAXNG_EXCEPT:
2658 case XML_RELAXNG_ATTRIBUTE:
2659 case XML_RELAXNG_INTERLEAVE:
2660 return(0);
2661 case XML_RELAXNG_NOT_ALLOWED:
2662 return(-1);
2663 }
2664 return(-1);
2665}
2666
2667/************************************************************************
2668 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002669 * Parsing functions *
2670 * *
2671 ************************************************************************/
2672
2673static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2674 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2675static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2676 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2677static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002678 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002679static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2680 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002681static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2682 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002683static int xmlRelaxNGParseGrammarContent(
2684 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002685static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2686 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2687 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002688static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2689 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002690static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2691 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002692
2693
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002694#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002695
2696/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002697 * xmlRelaxNGIsNullable:
2698 * @define: the definition to verify
2699 *
2700 * Check if a definition is nullable.
2701 *
2702 * Returns 1 if yes, 0 if no and -1 in case of error
2703 */
2704static int
2705xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2706 int ret;
2707 if (define == NULL)
2708 return(-1);
2709
Daniel Veillarde063f482003-03-21 16:53:17 +00002710 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002711 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00002712 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002713 return(0);
2714 switch (define->type) {
2715 case XML_RELAXNG_EMPTY:
2716 case XML_RELAXNG_TEXT:
2717 ret = 1; break;
2718 case XML_RELAXNG_NOOP:
2719 case XML_RELAXNG_DEF:
2720 case XML_RELAXNG_REF:
2721 case XML_RELAXNG_EXTERNALREF:
2722 case XML_RELAXNG_PARENTREF:
2723 case XML_RELAXNG_ONEORMORE:
2724 ret = xmlRelaxNGIsNullable(define->content);
2725 break;
2726 case XML_RELAXNG_EXCEPT:
2727 case XML_RELAXNG_NOT_ALLOWED:
2728 case XML_RELAXNG_ELEMENT:
2729 case XML_RELAXNG_DATATYPE:
2730 case XML_RELAXNG_PARAM:
2731 case XML_RELAXNG_VALUE:
2732 case XML_RELAXNG_LIST:
2733 case XML_RELAXNG_ATTRIBUTE:
2734 ret = 0; break;
2735 case XML_RELAXNG_CHOICE: {
2736 xmlRelaxNGDefinePtr list = define->content;
2737
2738 while (list != NULL) {
2739 ret = xmlRelaxNGIsNullable(list);
2740 if (ret != 0)
2741 goto done;
2742 list = list->next;
2743 }
2744 ret = 0; break;
2745 }
2746 case XML_RELAXNG_START:
2747 case XML_RELAXNG_INTERLEAVE:
2748 case XML_RELAXNG_GROUP: {
2749 xmlRelaxNGDefinePtr list = define->content;
2750
2751 while (list != NULL) {
2752 ret = xmlRelaxNGIsNullable(list);
2753 if (ret != 1)
2754 goto done;
2755 list = list->next;
2756 }
2757 return(1);
2758 }
2759 default:
2760 return(-1);
2761 }
2762done:
2763 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00002764 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002765 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00002766 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002767 return(ret);
2768}
2769
2770/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002771 * xmlRelaxNGIsBlank:
2772 * @str: a string
2773 *
2774 * Check if a string is ignorable c.f. 4.2. Whitespace
2775 *
2776 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2777 */
2778static int
2779xmlRelaxNGIsBlank(xmlChar *str) {
2780 if (str == NULL)
2781 return(1);
2782 while (*str != 0) {
2783 if (!(IS_BLANK(*str))) return(0);
2784 str++;
2785 }
2786 return(1);
2787}
2788
Daniel Veillard6eadf632003-01-23 18:29:16 +00002789/**
2790 * xmlRelaxNGGetDataTypeLibrary:
2791 * @ctxt: a Relax-NG parser context
2792 * @node: the current data or value element
2793 *
2794 * Applies algorithm from 4.3. datatypeLibrary attribute
2795 *
2796 * Returns the datatypeLibary value or NULL if not found
2797 */
2798static xmlChar *
2799xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2800 xmlNodePtr node) {
2801 xmlChar *ret, *escape;
2802
Daniel Veillard6eadf632003-01-23 18:29:16 +00002803 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2804 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2805 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002806 if (ret[0] == 0) {
2807 xmlFree(ret);
2808 return(NULL);
2809 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002810 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002811 if (escape == NULL) {
2812 return(ret);
2813 }
2814 xmlFree(ret);
2815 return(escape);
2816 }
2817 }
2818 node = node->parent;
2819 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002820 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2821 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002822 if (ret[0] == 0) {
2823 xmlFree(ret);
2824 return(NULL);
2825 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002826 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2827 if (escape == NULL) {
2828 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002829 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002830 xmlFree(ret);
2831 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002832 }
2833 node = node->parent;
2834 }
2835 return(NULL);
2836}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002837
2838/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002839 * xmlRelaxNGParseValue:
2840 * @ctxt: a Relax-NG parser context
2841 * @node: the data node.
2842 *
2843 * parse the content of a RelaxNG value node.
2844 *
2845 * Returns the definition pointer or NULL in case of error
2846 */
2847static xmlRelaxNGDefinePtr
2848xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2849 xmlRelaxNGDefinePtr def = NULL;
2850 xmlRelaxNGTypeLibraryPtr lib;
2851 xmlChar *type;
2852 xmlChar *library;
2853 int tmp;
2854
Daniel Veillardfd573f12003-03-16 17:52:32 +00002855 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002856 if (def == NULL)
2857 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002858 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002859
2860 type = xmlGetProp(node, BAD_CAST "type");
2861 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002862 xmlRelaxNGNormExtSpace(type);
2863 if (xmlValidateNCName(type, 0)) {
2864 if (ctxt->error != NULL)
2865 ctxt->error(ctxt->userData,
2866 "value type '%s' is not an NCName\n",
2867 type);
2868 ctxt->nbErrors++;
2869 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002870 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2871 if (library == NULL)
2872 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2873
2874 def->name = type;
2875 def->ns = library;
2876
2877 lib = (xmlRelaxNGTypeLibraryPtr)
2878 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2879 if (lib == NULL) {
2880 if (ctxt->error != NULL)
2881 ctxt->error(ctxt->userData,
2882 "Use of unregistered type library '%s'\n",
2883 library);
2884 ctxt->nbErrors++;
2885 def->data = NULL;
2886 } else {
2887 def->data = lib;
2888 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002889 if (ctxt->error != NULL)
2890 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002891 "Internal error with type library '%s': no 'have'\n",
2892 library);
2893 ctxt->nbErrors++;
2894 } else {
2895 tmp = lib->have(lib->data, def->name);
2896 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002897 if (ctxt->error != NULL)
2898 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002899 "Error type '%s' is not exported by type library '%s'\n",
2900 def->name, library);
2901 ctxt->nbErrors++;
2902 }
2903 }
2904 }
2905 }
2906 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002907 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002908 } else if (((node->children->type != XML_TEXT_NODE) &&
2909 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002910 (node->children->next != NULL)) {
2911 if (ctxt->error != NULL)
2912 ctxt->error(ctxt->userData,
2913 "Expecting a single text value for <value>content\n");
2914 ctxt->nbErrors++;
2915 } else {
2916 def->value = xmlNodeGetContent(node);
2917 if (def->value == NULL) {
2918 if (ctxt->error != NULL)
2919 ctxt->error(ctxt->userData,
2920 "Element <value> has no content\n");
2921 ctxt->nbErrors++;
2922 }
2923 }
2924 /* TODO check ahead of time that the value is okay per the type */
2925 return(def);
2926}
2927
2928/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002929 * xmlRelaxNGParseData:
2930 * @ctxt: a Relax-NG parser context
2931 * @node: the data node.
2932 *
2933 * parse the content of a RelaxNG data node.
2934 *
2935 * Returns the definition pointer or NULL in case of error
2936 */
2937static xmlRelaxNGDefinePtr
2938xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002939 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002940 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002941 xmlRelaxNGTypeLibraryPtr lib;
2942 xmlChar *type;
2943 xmlChar *library;
2944 xmlNodePtr content;
2945 int tmp;
2946
2947 type = xmlGetProp(node, BAD_CAST "type");
2948 if (type == NULL) {
2949 if (ctxt->error != NULL)
2950 ctxt->error(ctxt->userData,
2951 "data has no type\n");
2952 ctxt->nbErrors++;
2953 return(NULL);
2954 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002955 xmlRelaxNGNormExtSpace(type);
2956 if (xmlValidateNCName(type, 0)) {
2957 if (ctxt->error != NULL)
2958 ctxt->error(ctxt->userData,
2959 "data type '%s' is not an NCName\n",
2960 type);
2961 ctxt->nbErrors++;
2962 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002963 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2964 if (library == NULL)
2965 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2966
Daniel Veillardfd573f12003-03-16 17:52:32 +00002967 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002968 if (def == NULL) {
2969 xmlFree(type);
2970 return(NULL);
2971 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002972 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002973 def->name = type;
2974 def->ns = library;
2975
2976 lib = (xmlRelaxNGTypeLibraryPtr)
2977 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2978 if (lib == NULL) {
2979 if (ctxt->error != NULL)
2980 ctxt->error(ctxt->userData,
2981 "Use of unregistered type library '%s'\n",
2982 library);
2983 ctxt->nbErrors++;
2984 def->data = NULL;
2985 } else {
2986 def->data = lib;
2987 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002988 if (ctxt->error != NULL)
2989 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002990 "Internal error with type library '%s': no 'have'\n",
2991 library);
2992 ctxt->nbErrors++;
2993 } else {
2994 tmp = lib->have(lib->data, def->name);
2995 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002996 if (ctxt->error != NULL)
2997 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002998 "Error type '%s' is not exported by type library '%s'\n",
2999 def->name, library);
3000 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003001 } else if ((xmlStrEqual(library, BAD_CAST
3002 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3003 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3004 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3005 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003006 }
3007 }
3008 }
3009 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003010
3011 /*
3012 * Handle optional params
3013 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003014 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003015 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3016 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003017 if (xmlStrEqual(library,
3018 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3019 if (ctxt->error != NULL)
3020 ctxt->error(ctxt->userData,
3021 "Type library '%s' does not allow type parameters\n",
3022 library);
3023 ctxt->nbErrors++;
3024 content = content->next;
3025 while ((content != NULL) &&
3026 (xmlStrEqual(content->name, BAD_CAST "param")))
3027 content = content->next;
3028 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003029 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003030 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003031 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003032 param->name = xmlGetProp(content, BAD_CAST "name");
3033 if (param->name == NULL) {
3034 if (ctxt->error != NULL)
3035 ctxt->error(ctxt->userData,
3036 "param has no name\n");
3037 ctxt->nbErrors++;
3038 }
3039 param->value = xmlNodeGetContent(content);
3040 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003041 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003042 } else {
3043 lastparam->next = param;
3044 lastparam = param;
3045 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003046 if (lib != NULL) {
3047 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003048 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003049 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003050 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003051 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003052 /*
3053 * Handle optional except
3054 */
3055 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3056 xmlNodePtr child;
3057 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3058
Daniel Veillardfd573f12003-03-16 17:52:32 +00003059 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003060 if (except == NULL) {
3061 return(def);
3062 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003063 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003064 child = content->children;
3065 if (last == NULL) {
3066 def->content = except;
3067 } else {
3068 last->next = except;
3069 }
3070 if (child == NULL) {
3071 if (ctxt->error != NULL)
3072 ctxt->error(ctxt->userData,
3073 "except has no content\n");
3074 ctxt->nbErrors++;
3075 }
3076 while (child != NULL) {
3077 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3078 if (tmp2 != NULL) {
3079 if (last2 == NULL) {
3080 except->content = last2 = tmp2;
3081 } else {
3082 last2->next = tmp2;
3083 last2 = tmp2;
3084 }
3085 }
3086 child = child->next;
3087 }
3088 content = content->next;
3089 }
3090 /*
3091 * Check there is no unhandled data
3092 */
3093 if (content != NULL) {
3094 if (ctxt->error != NULL)
3095 ctxt->error(ctxt->userData,
3096 "Element data has unexpected content %s\n", content->name);
3097 ctxt->nbErrors++;
3098 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003099
3100 return(def);
3101}
3102
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003103static const xmlChar *invalidName = BAD_CAST "\1";
3104
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003105/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003106 * xmlRelaxNGCompareNameClasses:
3107 * @defs1: the first element/attribute defs
3108 * @defs2: the second element/attribute defs
3109 * @name: the restriction on the name
3110 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003111 *
3112 * Compare the 2 lists of element definitions. The comparison is
3113 * that if both lists do not accept the same QNames, it returns 1
3114 * If the 2 lists can accept the same QName the comparison returns 0
3115 *
3116 * Returns 1 disttinct, 0 if equal
3117 */
3118static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003119xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3120 xmlRelaxNGDefinePtr def2) {
3121 int ret = 1;
3122 xmlNode node;
3123 xmlNs ns;
3124 xmlRelaxNGValidCtxt ctxt;
3125 ctxt.flags = FLAGS_IGNORABLE;
3126
Daniel Veillard42f12e92003-03-07 18:32:59 +00003127 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3128
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003129 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3130 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3131 if (def2->type == XML_RELAXNG_TEXT)
3132 return(1);
3133 if (def1->name != NULL) {
3134 node.name = def1->name;
3135 } else {
3136 node.name = invalidName;
3137 }
3138 node.ns = &ns;
3139 if (def1->ns != NULL) {
3140 if (def1->ns[0] == 0) {
3141 node.ns = NULL;
3142 } else {
3143 ns.href = def1->ns;
3144 }
3145 } else {
3146 ns.href = invalidName;
3147 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003148 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003149 if (def1->nameClass != NULL) {
3150 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3151 } else {
3152 ret = 0;
3153 }
3154 } else {
3155 ret = 1;
3156 }
3157 } else if (def1->type == XML_RELAXNG_TEXT) {
3158 if (def2->type == XML_RELAXNG_TEXT)
3159 return(0);
3160 return(1);
3161 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003162 TODO
3163 ret = 0;
3164 } else {
3165 TODO
3166 ret = 0;
3167 }
3168 if (ret == 0)
3169 return(ret);
3170 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3171 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3172 if (def2->name != NULL) {
3173 node.name = def2->name;
3174 } else {
3175 node.name = invalidName;
3176 }
3177 node.ns = &ns;
3178 if (def2->ns != NULL) {
3179 if (def2->ns[0] == 0) {
3180 node.ns = NULL;
3181 } else {
3182 ns.href = def2->ns;
3183 }
3184 } else {
3185 ns.href = invalidName;
3186 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003187 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003188 if (def2->nameClass != NULL) {
3189 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3190 } else {
3191 ret = 0;
3192 }
3193 } else {
3194 ret = 1;
3195 }
3196 } else {
3197 TODO
3198 ret = 0;
3199 }
3200
3201 return(ret);
3202}
3203
3204/**
3205 * xmlRelaxNGCompareElemDefLists:
3206 * @ctxt: a Relax-NG parser context
3207 * @defs1: the first list of element/attribute defs
3208 * @defs2: the second list of element/attribute defs
3209 *
3210 * Compare the 2 lists of element or attribute definitions. The comparison
3211 * is that if both lists do not accept the same QNames, it returns 1
3212 * If the 2 lists can accept the same QName the comparison returns 0
3213 *
3214 * Returns 1 disttinct, 0 if equal
3215 */
3216static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003217xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3218 xmlRelaxNGDefinePtr *def1,
3219 xmlRelaxNGDefinePtr *def2) {
3220 xmlRelaxNGDefinePtr *basedef2 = def2;
3221
Daniel Veillard154877e2003-01-30 12:17:05 +00003222 if ((def1 == NULL) || (def2 == NULL))
3223 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003224 if ((*def1 == NULL) || (*def2 == NULL))
3225 return(1);
3226 while (*def1 != NULL) {
3227 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003228 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3229 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003230 def2++;
3231 }
3232 def2 = basedef2;
3233 def1++;
3234 }
3235 return(1);
3236}
3237
3238/**
3239 * xmlRelaxNGGetElements:
3240 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003241 * @def: the definition definition
3242 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003243 *
3244 * Compute the list of top elements a definition can generate
3245 *
3246 * Returns a list of elements or NULL if none was found.
3247 */
3248static xmlRelaxNGDefinePtr *
3249xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003250 xmlRelaxNGDefinePtr def,
3251 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003252 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003253 int len = 0;
3254 int max = 0;
3255
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003256 /*
3257 * Don't run that check in case of error. Infinite recursion
3258 * becomes possible.
3259 */
3260 if (ctxt->nbErrors != 0)
3261 return(NULL);
3262
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003263 parent = NULL;
3264 cur = def;
3265 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003266 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3267 (cur->type == XML_RELAXNG_TEXT))) ||
3268 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003269 if (ret == NULL) {
3270 max = 10;
3271 ret = (xmlRelaxNGDefinePtr *)
3272 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3273 if (ret == NULL) {
3274 if (ctxt->error != NULL)
3275 ctxt->error(ctxt->userData,
3276 "Out of memory in element search\n");
3277 ctxt->nbErrors++;
3278 return(NULL);
3279 }
3280 } else if (max <= len) {
3281 max *= 2;
3282 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3283 if (ret == NULL) {
3284 if (ctxt->error != NULL)
3285 ctxt->error(ctxt->userData,
3286 "Out of memory in element search\n");
3287 ctxt->nbErrors++;
3288 return(NULL);
3289 }
3290 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003291 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003292 ret[len] = NULL;
3293 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3294 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3295 (cur->type == XML_RELAXNG_GROUP) ||
3296 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003297 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3298 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003299 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003300 (cur->type == XML_RELAXNG_REF) ||
3301 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003302 /*
3303 * Don't go within elements or attributes or string values.
3304 * Just gather the element top list
3305 */
3306 if (cur->content != NULL) {
3307 parent = cur;
3308 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003309 tmp = cur;
3310 while (tmp != NULL) {
3311 tmp->parent = parent;
3312 tmp = tmp->next;
3313 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003314 continue;
3315 }
3316 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003317 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003318 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003319 if (cur->next != NULL) {
3320 cur = cur->next;
3321 continue;
3322 }
3323 do {
3324 cur = cur->parent;
3325 if (cur == NULL) break;
3326 if (cur == def) return(ret);
3327 if (cur->next != NULL) {
3328 cur = cur->next;
3329 break;
3330 }
3331 } while (cur != NULL);
3332 }
3333 return(ret);
3334}
3335
3336/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003337 * xmlRelaxNGCheckChoiceDeterminism:
3338 * @ctxt: a Relax-NG parser context
3339 * @def: the choice definition
3340 *
3341 * Also used to find indeterministic pattern in choice
3342 */
3343static void
3344xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3345 xmlRelaxNGDefinePtr def) {
3346 xmlRelaxNGDefinePtr **list;
3347 xmlRelaxNGDefinePtr cur;
3348 int nbchild = 0, i, j, ret;
3349 int is_nullable = 0;
3350 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003351 xmlHashTablePtr triage = NULL;
3352 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003353
3354 if ((def == NULL) ||
3355 (def->type != XML_RELAXNG_CHOICE))
3356 return;
3357
Daniel Veillarde063f482003-03-21 16:53:17 +00003358 if (def->dflags & IS_PROCESSED)
3359 return;
3360
Daniel Veillardfd573f12003-03-16 17:52:32 +00003361 /*
3362 * Don't run that check in case of error. Infinite recursion
3363 * becomes possible.
3364 */
3365 if (ctxt->nbErrors != 0)
3366 return;
3367
3368 is_nullable = xmlRelaxNGIsNullable(def);
3369
3370 cur = def->content;
3371 while (cur != NULL) {
3372 nbchild++;
3373 cur = cur->next;
3374 }
3375
3376 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3377 sizeof(xmlRelaxNGDefinePtr *));
3378 if (list == NULL) {
3379 if (ctxt->error != NULL)
3380 ctxt->error(ctxt->userData,
3381 "Out of memory in choice computation\n");
3382 ctxt->nbErrors++;
3383 return;
3384 }
3385 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003386 /*
3387 * a bit strong but safe
3388 */
3389 if (is_nullable == 0) {
3390 triage = xmlHashCreate(10);
3391 } else {
3392 is_triable = 0;
3393 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003394 cur = def->content;
3395 while (cur != NULL) {
3396 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003397 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3398 is_triable = 0;
3399 } else if (is_triable == 1) {
3400 xmlRelaxNGDefinePtr *tmp;
3401 int res;
3402
3403 tmp = list[i];
3404 while ((*tmp != NULL) && (is_triable == 1)) {
3405 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3406 res = xmlHashAddEntry2(triage,
3407 BAD_CAST "#text", NULL,
3408 (void *)cur);
3409 if (res != 0)
3410 is_triable = -1;
3411 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3412 ((*tmp)->name != NULL)) {
3413 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3414 res = xmlHashAddEntry2(triage,
3415 (*tmp)->name, NULL,
3416 (void *)cur);
3417 else
3418 res = xmlHashAddEntry2(triage,
3419 (*tmp)->name, (*tmp)->ns,
3420 (void *)cur);
3421 if (res != 0)
3422 is_triable = -1;
3423 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3424 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3425 res = xmlHashAddEntry2(triage,
3426 BAD_CAST "#any", NULL,
3427 (void *)cur);
3428 else
3429 res = xmlHashAddEntry2(triage,
3430 BAD_CAST "#any", (*tmp)->ns,
3431 (void *)cur);
3432 if (res != 0)
3433 is_triable = -1;
3434 } else {
3435 is_triable = -1;
3436 }
3437 tmp++;
3438 }
3439 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003440 i++;
3441 cur = cur->next;
3442 }
3443
3444 for (i = 0;i < nbchild;i++) {
3445 if (list[i] == NULL)
3446 continue;
3447 for (j = 0;j < i;j++) {
3448 if (list[j] == NULL)
3449 continue;
3450 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3451 if (ret == 0) {
3452 is_indeterminist = 1;
3453 }
3454 }
3455 }
3456 for (i = 0;i < nbchild;i++) {
3457 if (list[i] != NULL)
3458 xmlFree(list[i]);
3459 }
3460
3461 xmlFree(list);
3462 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003463 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003464 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003465 if (is_triable == 1) {
3466 def->dflags |= IS_TRIABLE;
3467 def->data = triage;
3468 } else if (triage != NULL) {
3469 xmlHashFree(triage, NULL);
3470 }
3471 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003472}
3473
3474/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003475 * xmlRelaxNGCheckGroupAttrs:
3476 * @ctxt: a Relax-NG parser context
3477 * @def: the group definition
3478 *
3479 * Detects violations of rule 7.3
3480 */
3481static void
3482xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3483 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003484 xmlRelaxNGDefinePtr **list;
3485 xmlRelaxNGDefinePtr cur;
3486 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003487
3488 if ((def == NULL) ||
3489 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003490 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003491 return;
3492
Daniel Veillarde063f482003-03-21 16:53:17 +00003493 if (def->dflags & IS_PROCESSED)
3494 return;
3495
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003496 /*
3497 * Don't run that check in case of error. Infinite recursion
3498 * becomes possible.
3499 */
3500 if (ctxt->nbErrors != 0)
3501 return;
3502
Daniel Veillardfd573f12003-03-16 17:52:32 +00003503 cur = def->attrs;
3504 while (cur != NULL) {
3505 nbchild++;
3506 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003507 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003508 cur = def->content;
3509 while (cur != NULL) {
3510 nbchild++;
3511 cur = cur->next;
3512 }
3513
3514 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3515 sizeof(xmlRelaxNGDefinePtr *));
3516 if (list == NULL) {
3517 if (ctxt->error != NULL)
3518 ctxt->error(ctxt->userData,
3519 "Out of memory in group computation\n");
3520 ctxt->nbErrors++;
3521 return;
3522 }
3523 i = 0;
3524 cur = def->attrs;
3525 while (cur != NULL) {
3526 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3527 i++;
3528 cur = cur->next;
3529 }
3530 cur = def->content;
3531 while (cur != NULL) {
3532 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3533 i++;
3534 cur = cur->next;
3535 }
3536
3537 for (i = 0;i < nbchild;i++) {
3538 if (list[i] == NULL)
3539 continue;
3540 for (j = 0;j < i;j++) {
3541 if (list[j] == NULL)
3542 continue;
3543 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3544 if (ret == 0) {
3545 if (ctxt->error != NULL)
3546 ctxt->error(ctxt->userData,
3547 "Attributes conflicts in group\n");
3548 ctxt->nbErrors++;
3549 }
3550 }
3551 }
3552 for (i = 0;i < nbchild;i++) {
3553 if (list[i] != NULL)
3554 xmlFree(list[i]);
3555 }
3556
3557 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003558 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003559}
3560
3561/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003562 * xmlRelaxNGComputeInterleaves:
3563 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003564 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003565 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003566 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003567 * A lot of work for preprocessing interleave definitions
3568 * is potentially needed to get a decent execution speed at runtime
3569 * - trying to get a total order on the element nodes generated
3570 * by the interleaves, order the list of interleave definitions
3571 * following that order.
3572 * - if <text/> is used to handle mixed content, it is better to
3573 * flag this in the define and simplify the runtime checking
3574 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003575 */
3576static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003577xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3578 xmlRelaxNGParserCtxtPtr ctxt,
3579 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003580 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003581
Daniel Veillardfd573f12003-03-16 17:52:32 +00003582 xmlRelaxNGPartitionPtr partitions = NULL;
3583 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3584 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003585 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003586 int nbgroups = 0;
3587 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003588 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003589 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003590
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003591 /*
3592 * Don't run that check in case of error. Infinite recursion
3593 * becomes possible.
3594 */
3595 if (ctxt->nbErrors != 0)
3596 return;
3597
Daniel Veillardfd573f12003-03-16 17:52:32 +00003598#ifdef DEBUG_INTERLEAVE
3599 xmlGenericError(xmlGenericErrorContext,
3600 "xmlRelaxNGComputeInterleaves(%s)\n",
3601 name);
3602#endif
3603 cur = def->content;
3604 while (cur != NULL) {
3605 nbchild++;
3606 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003607 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003608
3609#ifdef DEBUG_INTERLEAVE
3610 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3611#endif
3612 groups = (xmlRelaxNGInterleaveGroupPtr *)
3613 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3614 if (groups == NULL)
3615 goto error;
3616 cur = def->content;
3617 while (cur != NULL) {
3618 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3619 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3620 if (groups[nbgroups] == NULL)
3621 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003622 if (cur->type == XML_RELAXNG_TEXT)
3623 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003624 groups[nbgroups]->rule = cur;
3625 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3626 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3627 nbgroups++;
3628 cur = cur->next;
3629 }
3630#ifdef DEBUG_INTERLEAVE
3631 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3632#endif
3633
3634 /*
3635 * Let's check that all rules makes a partitions according to 7.4
3636 */
3637 partitions = (xmlRelaxNGPartitionPtr)
3638 xmlMalloc(sizeof(xmlRelaxNGPartition));
3639 if (partitions == NULL)
3640 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00003641 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00003642 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003643 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003644 for (i = 0;i < nbgroups;i++) {
3645 group = groups[i];
3646 for (j = i+1;j < nbgroups;j++) {
3647 if (groups[j] == NULL)
3648 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003649
Daniel Veillardfd573f12003-03-16 17:52:32 +00003650 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3651 groups[j]->defs);
3652 if (ret == 0) {
3653 if (ctxt->error != NULL)
3654 ctxt->error(ctxt->userData,
3655 "Element or text conflicts in interleave\n");
3656 ctxt->nbErrors++;
3657 }
3658 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3659 groups[j]->attrs);
3660 if (ret == 0) {
3661 if (ctxt->error != NULL)
3662 ctxt->error(ctxt->userData,
3663 "Attributes conflicts in interleave\n");
3664 ctxt->nbErrors++;
3665 }
3666 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003667 tmp = group->defs;
3668 if ((tmp != NULL) && (*tmp != NULL)) {
3669 while (*tmp != NULL) {
3670 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3671 res = xmlHashAddEntry2(partitions->triage,
3672 BAD_CAST "#text", NULL,
3673 (void *)(i + 1));
3674 if (res != 0)
3675 is_determinist = -1;
3676 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3677 ((*tmp)->name != NULL)) {
3678 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3679 res = xmlHashAddEntry2(partitions->triage,
3680 (*tmp)->name, NULL,
3681 (void *)(i + 1));
3682 else
3683 res = xmlHashAddEntry2(partitions->triage,
3684 (*tmp)->name, (*tmp)->ns,
3685 (void *)(i + 1));
3686 if (res != 0)
3687 is_determinist = -1;
3688 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3689 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3690 res = xmlHashAddEntry2(partitions->triage,
3691 BAD_CAST "#any", NULL,
3692 (void *)(i + 1));
3693 else
3694 res = xmlHashAddEntry2(partitions->triage,
3695 BAD_CAST "#any", (*tmp)->ns,
3696 (void *)(i + 1));
3697 if ((*tmp)->nameClass != NULL)
3698 is_determinist = 2;
3699 if (res != 0)
3700 is_determinist = -1;
3701 } else {
3702 is_determinist = -1;
3703 }
3704 tmp++;
3705 }
3706 } else {
3707 is_determinist = 0;
3708 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003709 }
3710 partitions->groups = groups;
3711
3712 /*
3713 * and save the partition list back in the def
3714 */
3715 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003716 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003717 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003718 if (is_determinist == 1)
3719 partitions->flags = IS_DETERMINIST;
3720 if (is_determinist == 2)
3721 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003722 return;
3723
3724error:
3725 if (ctxt->error != NULL)
3726 ctxt->error(ctxt->userData,
3727 "Out of memory in interleave computation\n");
3728 ctxt->nbErrors++;
3729 if (groups != NULL) {
3730 for (i = 0;i < nbgroups;i++)
3731 if (groups[i] != NULL) {
3732 if (groups[i]->defs != NULL)
3733 xmlFree(groups[i]->defs);
3734 xmlFree(groups[i]);
3735 }
3736 xmlFree(groups);
3737 }
3738 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003739}
3740
3741/**
3742 * xmlRelaxNGParseInterleave:
3743 * @ctxt: a Relax-NG parser context
3744 * @node: the data node.
3745 *
3746 * parse the content of a RelaxNG interleave node.
3747 *
3748 * Returns the definition pointer or NULL in case of error
3749 */
3750static xmlRelaxNGDefinePtr
3751xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3752 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003753 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003754 xmlNodePtr child;
3755
Daniel Veillardfd573f12003-03-16 17:52:32 +00003756 def = xmlRelaxNGNewDefine(ctxt, node);
3757 if (def == NULL) {
3758 return(NULL);
3759 }
3760 def->type = XML_RELAXNG_INTERLEAVE;
3761
3762 if (ctxt->interleaves == NULL)
3763 ctxt->interleaves = xmlHashCreate(10);
3764 if (ctxt->interleaves == NULL) {
3765 if (ctxt->error != NULL)
3766 ctxt->error(ctxt->userData,
3767 "Failed to create interleaves hash table\n");
3768 ctxt->nbErrors++;
3769 } else {
3770 char name[32];
3771
3772 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3773 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3774 if (ctxt->error != NULL)
3775 ctxt->error(ctxt->userData,
3776 "Failed to add %s to hash table\n", name);
3777 ctxt->nbErrors++;
3778 }
3779 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003780 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003781 if (child == NULL) {
3782 if (ctxt->error != NULL)
3783 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3784 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003785 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003786 while (child != NULL) {
3787 if (IS_RELAXNG(child, "element")) {
3788 cur = xmlRelaxNGParseElement(ctxt, child);
3789 } else {
3790 cur = xmlRelaxNGParsePattern(ctxt, child);
3791 }
3792 if (cur != NULL) {
3793 cur->parent = def;
3794 if (last == NULL) {
3795 def->content = last = cur;
3796 } else {
3797 last->next = cur;
3798 last = cur;
3799 }
3800 }
3801 child = child->next;
3802 }
3803
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003804 return(def);
3805}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003806
3807/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003808 * xmlRelaxNGParseInclude:
3809 * @ctxt: a Relax-NG parser context
3810 * @node: the include node
3811 *
3812 * Integrate the content of an include node in the current grammar
3813 *
3814 * Returns 0 in case of success or -1 in case of error
3815 */
3816static int
3817xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3818 xmlRelaxNGIncludePtr incl;
3819 xmlNodePtr root;
3820 int ret = 0, tmp;
3821
3822 incl = node->_private;
3823 if (incl == NULL) {
3824 if (ctxt->error != NULL)
3825 ctxt->error(ctxt->userData,
3826 "Include node has no data\n");
3827 ctxt->nbErrors++;
3828 return(-1);
3829 }
3830 root = xmlDocGetRootElement(incl->doc);
3831 if (root == NULL) {
3832 if (ctxt->error != NULL)
3833 ctxt->error(ctxt->userData,
3834 "Include document is empty\n");
3835 ctxt->nbErrors++;
3836 return(-1);
3837 }
3838 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3839 if (ctxt->error != NULL)
3840 ctxt->error(ctxt->userData,
3841 "Include document root is not a grammar\n");
3842 ctxt->nbErrors++;
3843 return(-1);
3844 }
3845
3846 /*
3847 * Merge the definition from both the include and the internal list
3848 */
3849 if (root->children != NULL) {
3850 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3851 if (tmp != 0)
3852 ret = -1;
3853 }
3854 if (node->children != NULL) {
3855 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3856 if (tmp != 0)
3857 ret = -1;
3858 }
3859 return(ret);
3860}
3861
3862/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003863 * xmlRelaxNGParseDefine:
3864 * @ctxt: a Relax-NG parser context
3865 * @node: the define node
3866 *
3867 * parse the content of a RelaxNG define element node.
3868 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003869 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003870 */
3871static int
3872xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3873 xmlChar *name;
3874 int ret = 0, tmp;
3875 xmlRelaxNGDefinePtr def;
3876 const xmlChar *olddefine;
3877
3878 name = xmlGetProp(node, BAD_CAST "name");
3879 if (name == NULL) {
3880 if (ctxt->error != NULL)
3881 ctxt->error(ctxt->userData,
3882 "define has no name\n");
3883 ctxt->nbErrors++;
3884 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003885 xmlRelaxNGNormExtSpace(name);
3886 if (xmlValidateNCName(name, 0)) {
3887 if (ctxt->error != NULL)
3888 ctxt->error(ctxt->userData,
3889 "define name '%s' is not an NCName\n",
3890 name);
3891 ctxt->nbErrors++;
3892 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003893 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003894 if (def == NULL) {
3895 xmlFree(name);
3896 return(-1);
3897 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003898 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003899 def->name = name;
3900 if (node->children == NULL) {
3901 if (ctxt->error != NULL)
3902 ctxt->error(ctxt->userData,
3903 "define has no children\n");
3904 ctxt->nbErrors++;
3905 } else {
3906 olddefine = ctxt->define;
3907 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003908 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003909 ctxt->define = olddefine;
3910 }
3911 if (ctxt->grammar->defs == NULL)
3912 ctxt->grammar->defs = xmlHashCreate(10);
3913 if (ctxt->grammar->defs == NULL) {
3914 if (ctxt->error != NULL)
3915 ctxt->error(ctxt->userData,
3916 "Could not create definition hash\n");
3917 ctxt->nbErrors++;
3918 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003919 } else {
3920 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3921 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003922 xmlRelaxNGDefinePtr prev;
3923
3924 prev = xmlHashLookup(ctxt->grammar->defs, name);
3925 if (prev == NULL) {
3926 if (ctxt->error != NULL)
3927 ctxt->error(ctxt->userData,
3928 "Internal error on define aggregation of %s\n",
3929 name);
3930 ctxt->nbErrors++;
3931 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003932 } else {
3933 while (prev->nextHash != NULL)
3934 prev = prev->nextHash;
3935 prev->nextHash = def;
3936 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003937 }
3938 }
3939 }
3940 return(ret);
3941}
3942
3943/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003944 * xmlRelaxNGProcessExternalRef:
3945 * @ctxt: the parser context
3946 * @node: the externlRef node
3947 *
3948 * Process and compile an externlRef node
3949 *
3950 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3951 */
3952static xmlRelaxNGDefinePtr
3953xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3954 xmlRelaxNGDocumentPtr docu;
3955 xmlNodePtr root, tmp;
3956 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003957 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003958 xmlRelaxNGDefinePtr def;
3959
3960 docu = node->_private;
3961 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003962 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003963 if (def == NULL)
3964 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003965 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003966
3967 if (docu->content == NULL) {
3968 /*
3969 * Then do the parsing for good
3970 */
3971 root = xmlDocGetRootElement(docu->doc);
3972 if (root == NULL) {
3973 if (ctxt->error != NULL)
3974 ctxt->error(ctxt->userData,
3975 "xmlRelaxNGParse: %s is empty\n",
3976 ctxt->URL);
3977 ctxt->nbErrors++;
3978 return (NULL);
3979 }
3980 /*
3981 * ns transmission rules
3982 */
3983 ns = xmlGetProp(root, BAD_CAST "ns");
3984 if (ns == NULL) {
3985 tmp = node;
3986 while ((tmp != NULL) &&
3987 (tmp->type == XML_ELEMENT_NODE)) {
3988 ns = xmlGetProp(tmp, BAD_CAST "ns");
3989 if (ns != NULL) {
3990 break;
3991 }
3992 tmp = tmp->parent;
3993 }
3994 if (ns != NULL) {
3995 xmlSetProp(root, BAD_CAST "ns", ns);
3996 newNs = 1;
3997 xmlFree(ns);
3998 }
3999 } else {
4000 xmlFree(ns);
4001 }
4002
4003 /*
4004 * Parsing to get a precompiled schemas.
4005 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004006 oldflags = ctxt->flags;
4007 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004008 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004009 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004010 if ((docu->schema != NULL) &&
4011 (docu->schema->topgrammar != NULL)) {
4012 docu->content = docu->schema->topgrammar->start;
4013 }
4014
4015 /*
4016 * the externalRef may be reused in a different ns context
4017 */
4018 if (newNs == 1) {
4019 xmlUnsetProp(root, BAD_CAST "ns");
4020 }
4021 }
4022 def->content = docu->content;
4023 } else {
4024 def = NULL;
4025 }
4026 return(def);
4027}
4028
4029/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004030 * xmlRelaxNGParsePattern:
4031 * @ctxt: a Relax-NG parser context
4032 * @node: the pattern node.
4033 *
4034 * parse the content of a RelaxNG pattern node.
4035 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004036 * Returns the definition pointer or NULL in case of error or if no
4037 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004038 */
4039static xmlRelaxNGDefinePtr
4040xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4041 xmlRelaxNGDefinePtr def = NULL;
4042
Daniel Veillardd2298792003-02-14 16:54:11 +00004043 if (node == NULL) {
4044 return(NULL);
4045 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004046 if (IS_RELAXNG(node, "element")) {
4047 def = xmlRelaxNGParseElement(ctxt, node);
4048 } else if (IS_RELAXNG(node, "attribute")) {
4049 def = xmlRelaxNGParseAttribute(ctxt, node);
4050 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004051 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004052 if (def == NULL)
4053 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004054 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004055 if (node->children != NULL) {
4056 if (ctxt->error != NULL)
4057 ctxt->error(ctxt->userData, "empty: had a child node\n");
4058 ctxt->nbErrors++;
4059 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004060 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004061 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004062 if (def == NULL)
4063 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004064 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004065 if (node->children != NULL) {
4066 if (ctxt->error != NULL)
4067 ctxt->error(ctxt->userData, "text: had a child node\n");
4068 ctxt->nbErrors++;
4069 }
4070 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004071 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004072 if (def == NULL)
4073 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004074 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004075 if (node->children == NULL) {
4076 if (ctxt->error != NULL)
4077 ctxt->error(ctxt->userData,
4078 "Element %s is empty\n", node->name);
4079 ctxt->nbErrors++;
4080 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004081 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004082 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004083 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004084 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004085 if (def == NULL)
4086 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004087 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004088 if (node->children == NULL) {
4089 if (ctxt->error != NULL)
4090 ctxt->error(ctxt->userData,
4091 "Element %s is empty\n", node->name);
4092 ctxt->nbErrors++;
4093 } else {
4094 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4095 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004096 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004097 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004098 if (def == NULL)
4099 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004100 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004101 if (node->children == NULL) {
4102 if (ctxt->error != NULL)
4103 ctxt->error(ctxt->userData,
4104 "Element %s is empty\n", node->name);
4105 ctxt->nbErrors++;
4106 } else {
4107 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4108 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004109 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004110 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004111 if (def == NULL)
4112 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004113 def->type = XML_RELAXNG_CHOICE;
4114 if (node->children == NULL) {
4115 if (ctxt->error != NULL)
4116 ctxt->error(ctxt->userData,
4117 "Element %s is empty\n", node->name);
4118 ctxt->nbErrors++;
4119 } else {
4120 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4121 }
4122 } else if (IS_RELAXNG(node, "group")) {
4123 def = xmlRelaxNGNewDefine(ctxt, node);
4124 if (def == NULL)
4125 return(NULL);
4126 def->type = XML_RELAXNG_GROUP;
4127 if (node->children == NULL) {
4128 if (ctxt->error != NULL)
4129 ctxt->error(ctxt->userData,
4130 "Element %s is empty\n", node->name);
4131 ctxt->nbErrors++;
4132 } else {
4133 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4134 }
4135 } else if (IS_RELAXNG(node, "ref")) {
4136 def = xmlRelaxNGNewDefine(ctxt, node);
4137 if (def == NULL)
4138 return(NULL);
4139 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004140 def->name = xmlGetProp(node, BAD_CAST "name");
4141 if (def->name == NULL) {
4142 if (ctxt->error != NULL)
4143 ctxt->error(ctxt->userData,
4144 "ref has no name\n");
4145 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004146 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004147 xmlRelaxNGNormExtSpace(def->name);
4148 if (xmlValidateNCName(def->name, 0)) {
4149 if (ctxt->error != NULL)
4150 ctxt->error(ctxt->userData,
4151 "ref name '%s' is not an NCName\n",
4152 def->name);
4153 ctxt->nbErrors++;
4154 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004155 }
4156 if (node->children != NULL) {
4157 if (ctxt->error != NULL)
4158 ctxt->error(ctxt->userData,
4159 "ref is not empty\n");
4160 ctxt->nbErrors++;
4161 }
4162 if (ctxt->grammar->refs == NULL)
4163 ctxt->grammar->refs = xmlHashCreate(10);
4164 if (ctxt->grammar->refs == NULL) {
4165 if (ctxt->error != NULL)
4166 ctxt->error(ctxt->userData,
4167 "Could not create references hash\n");
4168 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004169 def = NULL;
4170 } else {
4171 int tmp;
4172
4173 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4174 if (tmp < 0) {
4175 xmlRelaxNGDefinePtr prev;
4176
4177 prev = (xmlRelaxNGDefinePtr)
4178 xmlHashLookup(ctxt->grammar->refs, def->name);
4179 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004180 if (def->name != NULL) {
4181 if (ctxt->error != NULL)
4182 ctxt->error(ctxt->userData,
4183 "Error refs definitions '%s'\n",
4184 def->name);
4185 } else {
4186 if (ctxt->error != NULL)
4187 ctxt->error(ctxt->userData,
4188 "Error refs definitions\n");
4189 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004190 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004191 def = NULL;
4192 } else {
4193 def->nextHash = prev->nextHash;
4194 prev->nextHash = def;
4195 }
4196 }
4197 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004198 } else if (IS_RELAXNG(node, "data")) {
4199 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004200 } else if (IS_RELAXNG(node, "value")) {
4201 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004202 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004203 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004204 if (def == NULL)
4205 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004206 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004207 if (node->children == NULL) {
4208 if (ctxt->error != NULL)
4209 ctxt->error(ctxt->userData,
4210 "Element %s is empty\n", node->name);
4211 ctxt->nbErrors++;
4212 } else {
4213 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4214 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004215 } else if (IS_RELAXNG(node, "interleave")) {
4216 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004217 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004218 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004219 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004220 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004221 if (def == NULL)
4222 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004223 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004224 if (node->children != NULL) {
4225 if (ctxt->error != NULL)
4226 ctxt->error(ctxt->userData,
4227 "xmlRelaxNGParse: notAllowed element is not empty\n");
4228 ctxt->nbErrors++;
4229 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004230 } else if (IS_RELAXNG(node, "grammar")) {
4231 xmlRelaxNGGrammarPtr grammar, old;
4232 xmlRelaxNGGrammarPtr oldparent;
4233
Daniel Veillardc482e262003-02-26 14:48:48 +00004234#ifdef DEBUG_GRAMMAR
4235 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4236#endif
4237
Daniel Veillard419a7682003-02-03 23:22:49 +00004238 oldparent = ctxt->parentgrammar;
4239 old = ctxt->grammar;
4240 ctxt->parentgrammar = old;
4241 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4242 if (old != NULL) {
4243 ctxt->grammar = old;
4244 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004245#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004246 if (grammar != NULL) {
4247 grammar->next = old->next;
4248 old->next = grammar;
4249 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004250#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004251 }
4252 if (grammar != NULL)
4253 def = grammar->start;
4254 else
4255 def = NULL;
4256 } else if (IS_RELAXNG(node, "parentRef")) {
4257 if (ctxt->parentgrammar == NULL) {
4258 if (ctxt->error != NULL)
4259 ctxt->error(ctxt->userData,
4260 "Use of parentRef without a parent grammar\n");
4261 ctxt->nbErrors++;
4262 return(NULL);
4263 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004264 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004265 if (def == NULL)
4266 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004267 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004268 def->name = xmlGetProp(node, BAD_CAST "name");
4269 if (def->name == NULL) {
4270 if (ctxt->error != NULL)
4271 ctxt->error(ctxt->userData,
4272 "parentRef has no name\n");
4273 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004274 } else {
4275 xmlRelaxNGNormExtSpace(def->name);
4276 if (xmlValidateNCName(def->name, 0)) {
4277 if (ctxt->error != NULL)
4278 ctxt->error(ctxt->userData,
4279 "parentRef name '%s' is not an NCName\n",
4280 def->name);
4281 ctxt->nbErrors++;
4282 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004283 }
4284 if (node->children != NULL) {
4285 if (ctxt->error != NULL)
4286 ctxt->error(ctxt->userData,
4287 "parentRef is not empty\n");
4288 ctxt->nbErrors++;
4289 }
4290 if (ctxt->parentgrammar->refs == NULL)
4291 ctxt->parentgrammar->refs = xmlHashCreate(10);
4292 if (ctxt->parentgrammar->refs == NULL) {
4293 if (ctxt->error != NULL)
4294 ctxt->error(ctxt->userData,
4295 "Could not create references hash\n");
4296 ctxt->nbErrors++;
4297 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004298 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004299 int tmp;
4300
4301 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4302 if (tmp < 0) {
4303 xmlRelaxNGDefinePtr prev;
4304
4305 prev = (xmlRelaxNGDefinePtr)
4306 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4307 if (prev == NULL) {
4308 if (ctxt->error != NULL)
4309 ctxt->error(ctxt->userData,
4310 "Internal error parentRef definitions '%s'\n",
4311 def->name);
4312 ctxt->nbErrors++;
4313 def = NULL;
4314 } else {
4315 def->nextHash = prev->nextHash;
4316 prev->nextHash = def;
4317 }
4318 }
4319 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004320 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004321 if (node->children == NULL) {
4322 if (ctxt->error != NULL)
4323 ctxt->error(ctxt->userData,
4324 "Mixed is empty\n");
4325 ctxt->nbErrors++;
4326 def = NULL;
4327 } else {
4328 def = xmlRelaxNGParseInterleave(ctxt, node);
4329 if (def != NULL) {
4330 xmlRelaxNGDefinePtr tmp;
4331
4332 if ((def->content != NULL) && (def->content->next != NULL)) {
4333 tmp = xmlRelaxNGNewDefine(ctxt, node);
4334 if (tmp != NULL) {
4335 tmp->type = XML_RELAXNG_GROUP;
4336 tmp->content = def->content;
4337 def->content = tmp;
4338 }
4339 }
4340
4341 tmp = xmlRelaxNGNewDefine(ctxt, node);
4342 if (tmp == NULL)
4343 return(def);
4344 tmp->type = XML_RELAXNG_TEXT;
4345 tmp->next = def->content;
4346 def->content = tmp;
4347 }
4348 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004349 } else {
4350 if (ctxt->error != NULL)
4351 ctxt->error(ctxt->userData,
4352 "Unexpected node %s is not a pattern\n",
4353 node->name);
4354 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004355 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004356 }
4357 return(def);
4358}
4359
4360/**
4361 * xmlRelaxNGParseAttribute:
4362 * @ctxt: a Relax-NG parser context
4363 * @node: the element node
4364 *
4365 * parse the content of a RelaxNG attribute node.
4366 *
4367 * Returns the definition pointer or NULL in case of error.
4368 */
4369static xmlRelaxNGDefinePtr
4370xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004371 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004372 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004373 int old_flags;
4374
Daniel Veillardfd573f12003-03-16 17:52:32 +00004375 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004376 if (ret == NULL)
4377 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004378 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004379 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004380 child = node->children;
4381 if (child == NULL) {
4382 if (ctxt->error != NULL)
4383 ctxt->error(ctxt->userData,
4384 "xmlRelaxNGParseattribute: attribute has no children\n");
4385 ctxt->nbErrors++;
4386 return(ret);
4387 }
4388 old_flags = ctxt->flags;
4389 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004390 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4391 if (cur != NULL)
4392 child = child->next;
4393
Daniel Veillardd2298792003-02-14 16:54:11 +00004394 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004395 cur = xmlRelaxNGParsePattern(ctxt, child);
4396 if (cur != NULL) {
4397 switch (cur->type) {
4398 case XML_RELAXNG_EMPTY:
4399 case XML_RELAXNG_NOT_ALLOWED:
4400 case XML_RELAXNG_TEXT:
4401 case XML_RELAXNG_ELEMENT:
4402 case XML_RELAXNG_DATATYPE:
4403 case XML_RELAXNG_VALUE:
4404 case XML_RELAXNG_LIST:
4405 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004406 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004407 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004408 case XML_RELAXNG_DEF:
4409 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004410 case XML_RELAXNG_ZEROORMORE:
4411 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004412 case XML_RELAXNG_CHOICE:
4413 case XML_RELAXNG_GROUP:
4414 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004415 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004416 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004417 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004418 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004419 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004420 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004421 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004422 if (ctxt->error != NULL)
4423 ctxt->error(ctxt->userData,
4424 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004425 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004426 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004427 case XML_RELAXNG_NOOP:
4428 TODO
4429 if (ctxt->error != NULL)
4430 ctxt->error(ctxt->userData,
4431 "Internal error, noop found\n");
4432 ctxt->nbErrors++;
4433 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004434 }
4435 }
4436 child = child->next;
4437 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004438 if (child != NULL) {
4439 if (ctxt->error != NULL)
4440 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4441 ctxt->nbErrors++;
4442 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004443 ctxt->flags = old_flags;
4444 return(ret);
4445}
4446
4447/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004448 * xmlRelaxNGParseExceptNameClass:
4449 * @ctxt: a Relax-NG parser context
4450 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004451 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004452 *
4453 * parse the content of a RelaxNG nameClass node.
4454 *
4455 * Returns the definition pointer or NULL in case of error.
4456 */
4457static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004458xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4459 xmlNodePtr node, int attr) {
4460 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4461 xmlNodePtr child;
4462
Daniel Veillardd2298792003-02-14 16:54:11 +00004463 if (!IS_RELAXNG(node, "except")) {
4464 if (ctxt->error != NULL)
4465 ctxt->error(ctxt->userData,
4466 "Expecting an except node\n");
4467 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004468 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004469 }
4470 if (node->next != NULL) {
4471 if (ctxt->error != NULL)
4472 ctxt->error(ctxt->userData,
4473 "exceptNameClass allows only a single except node\n");
4474 ctxt->nbErrors++;
4475 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004476 if (node->children == NULL) {
4477 if (ctxt->error != NULL)
4478 ctxt->error(ctxt->userData,
4479 "except has no content\n");
4480 ctxt->nbErrors++;
4481 return(NULL);
4482 }
4483
Daniel Veillardfd573f12003-03-16 17:52:32 +00004484 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004485 if (ret == NULL)
4486 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004487 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004488 child = node->children;
4489 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004490 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004491 if (cur == NULL)
4492 break;
4493 if (attr)
4494 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004495 else
4496 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004497
Daniel Veillard419a7682003-02-03 23:22:49 +00004498 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004499 if (last == NULL) {
4500 ret->content = cur;
4501 } else {
4502 last->next = cur;
4503 }
4504 last = cur;
4505 }
4506 child = child->next;
4507 }
4508
4509 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004510}
4511
4512/**
4513 * xmlRelaxNGParseNameClass:
4514 * @ctxt: a Relax-NG parser context
4515 * @node: the nameClass node
4516 * @def: the current definition
4517 *
4518 * parse the content of a RelaxNG nameClass node.
4519 *
4520 * Returns the definition pointer or NULL in case of error.
4521 */
4522static xmlRelaxNGDefinePtr
4523xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4524 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004525 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004526 xmlChar *val;
4527
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004528 ret = def;
4529 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4530 (IS_RELAXNG(node, "nsName"))) {
4531 if ((def->type != XML_RELAXNG_ELEMENT) &&
4532 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004533 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004534 if (ret == NULL)
4535 return(NULL);
4536 ret->parent = def;
4537 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4538 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004539 else
4540 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004541 }
4542 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004543 if (IS_RELAXNG(node, "name")) {
4544 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004545 xmlRelaxNGNormExtSpace(val);
4546 if (xmlValidateNCName(val, 0)) {
4547 if (ctxt->error != NULL) {
4548 if (node->parent != NULL)
4549 ctxt->error(ctxt->userData,
4550 "Element %s name '%s' is not an NCName\n",
4551 node->parent->name, val);
4552 else
4553 ctxt->error(ctxt->userData,
4554 "name '%s' is not an NCName\n",
4555 val);
4556 }
4557 ctxt->nbErrors++;
4558 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004559 ret->name = val;
4560 val = xmlGetProp(node, BAD_CAST "ns");
4561 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004562 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4563 (val != NULL) &&
4564 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4565 ctxt->error(ctxt->userData,
4566 "Attribute with namespace '%s' is not allowed\n",
4567 val);
4568 ctxt->nbErrors++;
4569 }
4570 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4571 (val != NULL) &&
4572 (val[0] == 0) &&
4573 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4574 ctxt->error(ctxt->userData,
4575 "Attribute with QName 'xmlns' is not allowed\n",
4576 val);
4577 ctxt->nbErrors++;
4578 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004579 } else if (IS_RELAXNG(node, "anyName")) {
4580 ret->name = NULL;
4581 ret->ns = NULL;
4582 if (node->children != NULL) {
4583 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004584 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4585 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004586 }
4587 } else if (IS_RELAXNG(node, "nsName")) {
4588 ret->name = NULL;
4589 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4590 if (ret->ns == NULL) {
4591 if (ctxt->error != NULL)
4592 ctxt->error(ctxt->userData,
4593 "nsName has no ns attribute\n");
4594 ctxt->nbErrors++;
4595 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004596 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4597 (ret->ns != NULL) &&
4598 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4599 ctxt->error(ctxt->userData,
4600 "Attribute with namespace '%s' is not allowed\n",
4601 ret->ns);
4602 ctxt->nbErrors++;
4603 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004604 if (node->children != NULL) {
4605 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004606 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4607 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004608 }
4609 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004610 xmlNodePtr child;
4611 xmlRelaxNGDefinePtr last = NULL;
4612
4613 ret = xmlRelaxNGNewDefine(ctxt, node);
4614 if (ret == NULL)
4615 return(NULL);
4616 ret->parent = def;
4617 ret->type = XML_RELAXNG_CHOICE;
4618
Daniel Veillardd2298792003-02-14 16:54:11 +00004619 if (node->children == NULL) {
4620 if (ctxt->error != NULL)
4621 ctxt->error(ctxt->userData,
4622 "Element choice is empty\n");
4623 ctxt->nbErrors++;
4624 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004625
4626 child = node->children;
4627 while (child != NULL) {
4628 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4629 if (tmp != NULL) {
4630 if (last == NULL) {
4631 last = ret->nameClass = tmp;
4632 } else {
4633 last->next = tmp;
4634 last = tmp;
4635 }
4636 }
4637 child = child->next;
4638 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004639 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004640 } else {
4641 if (ctxt->error != NULL)
4642 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004643 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004644 node->name);
4645 ctxt->nbErrors++;
4646 return(NULL);
4647 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004648 if (ret != def) {
4649 if (def->nameClass == NULL) {
4650 def->nameClass = ret;
4651 } else {
4652 tmp = def->nameClass;
4653 while (tmp->next != NULL) {
4654 tmp = tmp->next;
4655 }
4656 tmp->next = ret;
4657 }
4658 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004659 return(ret);
4660}
4661
4662/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004663 * xmlRelaxNGParseElement:
4664 * @ctxt: a Relax-NG parser context
4665 * @node: the element node
4666 *
4667 * parse the content of a RelaxNG element node.
4668 *
4669 * Returns the definition pointer or NULL in case of error.
4670 */
4671static xmlRelaxNGDefinePtr
4672xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4673 xmlRelaxNGDefinePtr ret, cur, last;
4674 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004675 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004676
Daniel Veillardfd573f12003-03-16 17:52:32 +00004677 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004678 if (ret == NULL)
4679 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004680 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004681 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004682 child = node->children;
4683 if (child == NULL) {
4684 if (ctxt->error != NULL)
4685 ctxt->error(ctxt->userData,
4686 "xmlRelaxNGParseElement: element has no children\n");
4687 ctxt->nbErrors++;
4688 return(ret);
4689 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004690 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4691 if (cur != NULL)
4692 child = child->next;
4693
Daniel Veillard6eadf632003-01-23 18:29:16 +00004694 if (child == NULL) {
4695 if (ctxt->error != NULL)
4696 ctxt->error(ctxt->userData,
4697 "xmlRelaxNGParseElement: element has no content\n");
4698 ctxt->nbErrors++;
4699 return(ret);
4700 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004701 olddefine = ctxt->define;
4702 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004703 last = NULL;
4704 while (child != NULL) {
4705 cur = xmlRelaxNGParsePattern(ctxt, child);
4706 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004707 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004708 switch (cur->type) {
4709 case XML_RELAXNG_EMPTY:
4710 case XML_RELAXNG_NOT_ALLOWED:
4711 case XML_RELAXNG_TEXT:
4712 case XML_RELAXNG_ELEMENT:
4713 case XML_RELAXNG_DATATYPE:
4714 case XML_RELAXNG_VALUE:
4715 case XML_RELAXNG_LIST:
4716 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004717 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004718 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004719 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004720 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004721 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004722 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004723 case XML_RELAXNG_CHOICE:
4724 case XML_RELAXNG_GROUP:
4725 case XML_RELAXNG_INTERLEAVE:
4726 if (last == NULL) {
4727 ret->content = last = cur;
4728 } else {
4729 if ((last->type == XML_RELAXNG_ELEMENT) &&
4730 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004731 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004732 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004733 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004734 ret->content->content = last;
4735 } else {
4736 ret->content = last;
4737 }
4738 }
4739 last->next = cur;
4740 last = cur;
4741 }
4742 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004743 case XML_RELAXNG_ATTRIBUTE:
4744 cur->next = ret->attrs;
4745 ret->attrs = cur;
4746 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004747 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004748 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004749 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004750 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004751 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004752 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004753 case XML_RELAXNG_NOOP:
4754 TODO
4755 if (ctxt->error != NULL)
4756 ctxt->error(ctxt->userData,
4757 "Internal error, noop found\n");
4758 ctxt->nbErrors++;
4759 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004760 }
4761 }
4762 child = child->next;
4763 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004764 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004765 return(ret);
4766}
4767
4768/**
4769 * xmlRelaxNGParsePatterns:
4770 * @ctxt: a Relax-NG parser context
4771 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004772 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004773 *
4774 * parse the content of a RelaxNG start node.
4775 *
4776 * Returns the definition pointer or NULL in case of error.
4777 */
4778static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004779xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4780 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004781 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004782
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004783 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004784 while (nodes != NULL) {
4785 if (IS_RELAXNG(nodes, "element")) {
4786 cur = xmlRelaxNGParseElement(ctxt, nodes);
4787 if (def == NULL) {
4788 def = last = cur;
4789 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004790 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4791 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004792 def = xmlRelaxNGNewDefine(ctxt, nodes);
4793 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004794 def->content = last;
4795 }
4796 last->next = cur;
4797 last = cur;
4798 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004799 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004800 } else {
4801 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004802 if (cur != NULL) {
4803 if (def == NULL) {
4804 def = last = cur;
4805 } else {
4806 last->next = cur;
4807 last = cur;
4808 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004809 }
4810 }
4811 nodes = nodes->next;
4812 }
4813 return(def);
4814}
4815
4816/**
4817 * xmlRelaxNGParseStart:
4818 * @ctxt: a Relax-NG parser context
4819 * @nodes: start children nodes
4820 *
4821 * parse the content of a RelaxNG start node.
4822 *
4823 * Returns 0 in case of success, -1 in case of error
4824 */
4825static int
4826xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4827 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004828 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004829
Daniel Veillardd2298792003-02-14 16:54:11 +00004830 if (nodes == NULL) {
4831 if (ctxt->error != NULL)
4832 ctxt->error(ctxt->userData,
4833 "start has no children\n");
4834 ctxt->nbErrors++;
4835 return(-1);
4836 }
4837 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004838 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004839 if (def == NULL)
4840 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004841 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004842 if (nodes->children != NULL) {
4843 if (ctxt->error != NULL)
4844 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004845 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004846 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004847 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004848 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004849 if (def == NULL)
4850 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004851 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004852 if (nodes->children != NULL) {
4853 if (ctxt->error != NULL)
4854 ctxt->error(ctxt->userData,
4855 "element notAllowed is not empty\n");
4856 ctxt->nbErrors++;
4857 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004858 } else {
4859 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004860 }
4861 if (ctxt->grammar->start != NULL) {
4862 last = ctxt->grammar->start;
4863 while (last->next != NULL)
4864 last = last->next;
4865 last->next = def;
4866 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004867 ctxt->grammar->start = def;
4868 }
4869 nodes = nodes->next;
4870 if (nodes != NULL) {
4871 if (ctxt->error != NULL)
4872 ctxt->error(ctxt->userData,
4873 "start more than one children\n");
4874 ctxt->nbErrors++;
4875 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004876 }
4877 return(ret);
4878}
4879
4880/**
4881 * xmlRelaxNGParseGrammarContent:
4882 * @ctxt: a Relax-NG parser context
4883 * @nodes: grammar children nodes
4884 *
4885 * parse the content of a RelaxNG grammar node.
4886 *
4887 * Returns 0 in case of success, -1 in case of error
4888 */
4889static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004890xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004891{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004892 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004893
4894 if (nodes == NULL) {
4895 if (ctxt->error != NULL)
4896 ctxt->error(ctxt->userData,
4897 "grammar has no children\n");
4898 ctxt->nbErrors++;
4899 return(-1);
4900 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004901 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004902 if (IS_RELAXNG(nodes, "start")) {
4903 if (nodes->children == NULL) {
4904 if (ctxt->error != NULL)
4905 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004906 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004907 ctxt->nbErrors++;
4908 } else {
4909 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4910 if (tmp != 0)
4911 ret = -1;
4912 }
4913 } else if (IS_RELAXNG(nodes, "define")) {
4914 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4915 if (tmp != 0)
4916 ret = -1;
4917 } else if (IS_RELAXNG(nodes, "include")) {
4918 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4919 if (tmp != 0)
4920 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004921 } else {
4922 if (ctxt->error != NULL)
4923 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004924 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004925 ctxt->nbErrors++;
4926 ret = -1;
4927 }
4928 nodes = nodes->next;
4929 }
4930 return (ret);
4931}
4932
4933/**
4934 * xmlRelaxNGCheckReference:
4935 * @ref: the ref
4936 * @ctxt: a Relax-NG parser context
4937 * @name: the name associated to the defines
4938 *
4939 * Applies the 4.17. combine attribute rule for all the define
4940 * element of a given grammar using the same name.
4941 */
4942static void
4943xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4944 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4945 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004946 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004947
4948 grammar = ctxt->grammar;
4949 if (grammar == NULL) {
4950 if (ctxt->error != NULL)
4951 ctxt->error(ctxt->userData,
4952 "Internal error: no grammar in CheckReference %s\n",
4953 name);
4954 ctxt->nbErrors++;
4955 return;
4956 }
4957 if (ref->content != NULL) {
4958 if (ctxt->error != NULL)
4959 ctxt->error(ctxt->userData,
4960 "Internal error: reference has content in CheckReference %s\n",
4961 name);
4962 ctxt->nbErrors++;
4963 return;
4964 }
4965 if (grammar->defs != NULL) {
4966 def = xmlHashLookup(grammar->defs, name);
4967 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004968 cur = ref;
4969 while (cur != NULL) {
4970 cur->content = def;
4971 cur = cur->nextHash;
4972 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004973 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004974 if (ctxt->error != NULL)
4975 ctxt->error(ctxt->userData,
4976 "Reference %s has no matching definition\n",
4977 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004978 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004979 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004980 } else {
4981 if (ctxt->error != NULL)
4982 ctxt->error(ctxt->userData,
4983 "Reference %s has no matching definition\n",
4984 name);
4985 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004986 }
4987 /*
4988 * TODO: make a closure and verify there is no loop !
4989 */
4990}
4991
4992/**
4993 * xmlRelaxNGCheckCombine:
4994 * @define: the define(s) list
4995 * @ctxt: a Relax-NG parser context
4996 * @name: the name associated to the defines
4997 *
4998 * Applies the 4.17. combine attribute rule for all the define
4999 * element of a given grammar using the same name.
5000 */
5001static void
5002xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5003 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5004 xmlChar *combine;
5005 int choiceOrInterleave = -1;
5006 int missing = 0;
5007 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5008
5009 if (define->nextHash == NULL)
5010 return;
5011 cur = define;
5012 while (cur != NULL) {
5013 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5014 if (combine != NULL) {
5015 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5016 if (choiceOrInterleave == -1)
5017 choiceOrInterleave = 1;
5018 else if (choiceOrInterleave == 0) {
5019 if (ctxt->error != NULL)
5020 ctxt->error(ctxt->userData,
5021 "Defines for %s use both 'choice' and 'interleave'\n",
5022 name);
5023 ctxt->nbErrors++;
5024 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005025 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005026 if (choiceOrInterleave == -1)
5027 choiceOrInterleave = 0;
5028 else if (choiceOrInterleave == 1) {
5029 if (ctxt->error != NULL)
5030 ctxt->error(ctxt->userData,
5031 "Defines for %s use both 'choice' and 'interleave'\n",
5032 name);
5033 ctxt->nbErrors++;
5034 }
5035 } else {
5036 if (ctxt->error != NULL)
5037 ctxt->error(ctxt->userData,
5038 "Defines for %s use unknown combine value '%s''\n",
5039 name, combine);
5040 ctxt->nbErrors++;
5041 }
5042 xmlFree(combine);
5043 } else {
5044 if (missing == 0)
5045 missing = 1;
5046 else {
5047 if (ctxt->error != NULL)
5048 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005049 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005050 name);
5051 ctxt->nbErrors++;
5052 }
5053 }
5054
5055 cur = cur->nextHash;
5056 }
5057#ifdef DEBUG
5058 xmlGenericError(xmlGenericErrorContext,
5059 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5060 name, choiceOrInterleave);
5061#endif
5062 if (choiceOrInterleave == -1)
5063 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005064 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005065 if (cur == NULL)
5066 return;
5067 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005068 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005069 else
5070 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005071 tmp = define;
5072 last = NULL;
5073 while (tmp != NULL) {
5074 if (tmp->content != NULL) {
5075 if (tmp->content->next != NULL) {
5076 /*
5077 * we need first to create a wrapper.
5078 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005079 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005080 if (tmp2 == NULL)
5081 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005082 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005083 tmp2->content = tmp->content;
5084 } else {
5085 tmp2 = tmp->content;
5086 }
5087 if (last == NULL) {
5088 cur->content = tmp2;
5089 } else {
5090 last->next = tmp2;
5091 }
5092 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005093 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005094 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005095 tmp = tmp->nextHash;
5096 }
5097 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005098 if (choiceOrInterleave == 0) {
5099 if (ctxt->interleaves == NULL)
5100 ctxt->interleaves = xmlHashCreate(10);
5101 if (ctxt->interleaves == NULL) {
5102 if (ctxt->error != NULL)
5103 ctxt->error(ctxt->userData,
5104 "Failed to create interleaves hash table\n");
5105 ctxt->nbErrors++;
5106 } else {
5107 char tmpname[32];
5108
5109 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5110 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5111 if (ctxt->error != NULL)
5112 ctxt->error(ctxt->userData,
5113 "Failed to add %s to hash table\n", tmpname);
5114 ctxt->nbErrors++;
5115 }
5116 }
5117 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005118}
5119
5120/**
5121 * xmlRelaxNGCombineStart:
5122 * @ctxt: a Relax-NG parser context
5123 * @grammar: the grammar
5124 *
5125 * Applies the 4.17. combine rule for all the start
5126 * element of a given grammar.
5127 */
5128static void
5129xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5130 xmlRelaxNGGrammarPtr grammar) {
5131 xmlRelaxNGDefinePtr starts;
5132 xmlChar *combine;
5133 int choiceOrInterleave = -1;
5134 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005135 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005136
Daniel Veillard2df2de22003-02-17 23:34:33 +00005137 starts = grammar->start;
5138 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005139 return;
5140 cur = starts;
5141 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005142 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5143 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5144 combine = NULL;
5145 if (ctxt->error != NULL)
5146 ctxt->error(ctxt->userData,
5147 "Internal error: start element not found\n");
5148 ctxt->nbErrors++;
5149 } else {
5150 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5151 }
5152
Daniel Veillard6eadf632003-01-23 18:29:16 +00005153 if (combine != NULL) {
5154 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5155 if (choiceOrInterleave == -1)
5156 choiceOrInterleave = 1;
5157 else if (choiceOrInterleave == 0) {
5158 if (ctxt->error != NULL)
5159 ctxt->error(ctxt->userData,
5160 "<start> use both 'choice' and 'interleave'\n");
5161 ctxt->nbErrors++;
5162 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005163 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005164 if (choiceOrInterleave == -1)
5165 choiceOrInterleave = 0;
5166 else if (choiceOrInterleave == 1) {
5167 if (ctxt->error != NULL)
5168 ctxt->error(ctxt->userData,
5169 "<start> use both 'choice' and 'interleave'\n");
5170 ctxt->nbErrors++;
5171 }
5172 } else {
5173 if (ctxt->error != NULL)
5174 ctxt->error(ctxt->userData,
5175 "<start> uses unknown combine value '%s''\n", combine);
5176 ctxt->nbErrors++;
5177 }
5178 xmlFree(combine);
5179 } else {
5180 if (missing == 0)
5181 missing = 1;
5182 else {
5183 if (ctxt->error != NULL)
5184 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005185 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005186 ctxt->nbErrors++;
5187 }
5188 }
5189
Daniel Veillard2df2de22003-02-17 23:34:33 +00005190 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005191 }
5192#ifdef DEBUG
5193 xmlGenericError(xmlGenericErrorContext,
5194 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5195 choiceOrInterleave);
5196#endif
5197 if (choiceOrInterleave == -1)
5198 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005199 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005200 if (cur == NULL)
5201 return;
5202 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005203 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005204 else
5205 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005206 cur->content = grammar->start;
5207 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005208 if (choiceOrInterleave == 0) {
5209 if (ctxt->interleaves == NULL)
5210 ctxt->interleaves = xmlHashCreate(10);
5211 if (ctxt->interleaves == NULL) {
5212 if (ctxt->error != NULL)
5213 ctxt->error(ctxt->userData,
5214 "Failed to create interleaves hash table\n");
5215 ctxt->nbErrors++;
5216 } else {
5217 char tmpname[32];
5218
5219 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5220 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5221 if (ctxt->error != NULL)
5222 ctxt->error(ctxt->userData,
5223 "Failed to add %s to hash table\n", tmpname);
5224 ctxt->nbErrors++;
5225 }
5226 }
5227 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005228}
5229
5230/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005231 * xmlRelaxNGCheckCycles:
5232 * @ctxt: a Relax-NG parser context
5233 * @nodes: grammar children nodes
5234 * @depth: the counter
5235 *
5236 * Check for cycles.
5237 *
5238 * Returns 0 if check passed, and -1 in case of error
5239 */
5240static int
5241xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5242 xmlRelaxNGDefinePtr cur, int depth) {
5243 int ret = 0;
5244
5245 while ((ret == 0) && (cur != NULL)) {
5246 if ((cur->type == XML_RELAXNG_REF) ||
5247 (cur->type == XML_RELAXNG_PARENTREF)) {
5248 if (cur->depth == -1) {
5249 cur->depth = depth;
5250 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5251 cur->depth = -2;
5252 } else if (depth == cur->depth) {
5253 if (ctxt->error != NULL)
5254 ctxt->error(ctxt->userData,
5255 "Detected a cycle in %s references\n", cur->name);
5256 ctxt->nbErrors++;
5257 return(-1);
5258 }
5259 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5260 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5261 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005262 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005263 }
5264 cur = cur->next;
5265 }
5266 return(ret);
5267}
5268
5269/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005270 * xmlRelaxNGTryUnlink:
5271 * @ctxt: a Relax-NG parser context
5272 * @cur: the definition to unlink
5273 * @parent: the parent definition
5274 * @prev: the previous sibling definition
5275 *
5276 * Try to unlink a definition. If not possble make it a NOOP
5277 *
5278 * Returns the new prev definition
5279 */
5280static xmlRelaxNGDefinePtr
5281xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5282 xmlRelaxNGDefinePtr cur,
5283 xmlRelaxNGDefinePtr parent,
5284 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005285 if (prev != NULL) {
5286 prev->next = cur->next;
5287 } else {
5288 if (parent != NULL) {
5289 if (parent->content == cur)
5290 parent->content = cur->next;
5291 else if (parent->attrs == cur)
5292 parent->attrs = cur->next;
5293 else if (parent->nameClass == cur)
5294 parent->nameClass = cur->next;
5295 } else {
5296 cur->type = XML_RELAXNG_NOOP;
5297 prev = cur;
5298 }
5299 }
5300 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005301}
5302
5303/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005304 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005305 * @ctxt: a Relax-NG parser context
5306 * @nodes: grammar children nodes
5307 *
5308 * Check for simplification of empty and notAllowed
5309 */
5310static void
5311xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5312 xmlRelaxNGDefinePtr cur,
5313 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005314 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005315
Daniel Veillardfd573f12003-03-16 17:52:32 +00005316 while (cur != NULL) {
5317 if ((cur->type == XML_RELAXNG_REF) ||
5318 (cur->type == XML_RELAXNG_PARENTREF)) {
5319 if (cur->depth != -3) {
5320 cur->depth = -3;
5321 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005322 }
5323 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005324 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005325 if ((parent != NULL) &&
5326 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5327 (parent->type == XML_RELAXNG_LIST) ||
5328 (parent->type == XML_RELAXNG_GROUP) ||
5329 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005330 (parent->type == XML_RELAXNG_ONEORMORE) ||
5331 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005332 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005333 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005334 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005335 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005336 (parent->type == XML_RELAXNG_CHOICE)) {
5337 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5338 } else
5339 prev = cur;
5340 } else if (cur->type == XML_RELAXNG_EMPTY){
5341 cur->parent = parent;
5342 if ((parent != NULL) &&
5343 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5344 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005345 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005346 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005347 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005348 if ((parent != NULL) &&
5349 ((parent->type == XML_RELAXNG_GROUP) ||
5350 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5351 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5352 } else
5353 prev = cur;
5354 } else {
5355 cur->parent = parent;
5356 if (cur->content != NULL)
5357 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5358 if (cur->attrs != NULL)
5359 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5360 if (cur->nameClass != NULL)
5361 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5362 /*
5363 * This may result in a simplification
5364 */
5365 if ((cur->type == XML_RELAXNG_GROUP) ||
5366 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5367 if (cur->content == NULL)
5368 cur->type = XML_RELAXNG_EMPTY;
5369 else if (cur->content->next == NULL) {
5370 if ((parent == NULL) && (prev == NULL)) {
5371 cur->type = XML_RELAXNG_NOOP;
5372 } else if (prev == NULL) {
5373 parent->content = cur->content;
5374 cur->content->next = cur->next;
5375 cur = cur->content;
5376 } else {
5377 cur->content->next = cur->next;
5378 prev->next = cur->content;
5379 cur = cur->content;
5380 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005381 }
5382 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005383 /*
5384 * the current node may have been transformed back
5385 */
5386 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5387 (cur->content != NULL) &&
5388 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5389 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5390 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5391 if ((parent != NULL) &&
5392 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5393 (parent->type == XML_RELAXNG_LIST) ||
5394 (parent->type == XML_RELAXNG_GROUP) ||
5395 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5396 (parent->type == XML_RELAXNG_ONEORMORE) ||
5397 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5398 parent->type = XML_RELAXNG_NOT_ALLOWED;
5399 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005400 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005401 if ((parent != NULL) &&
5402 (parent->type == XML_RELAXNG_CHOICE)) {
5403 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5404 } else
5405 prev = cur;
5406 } else if (cur->type == XML_RELAXNG_EMPTY){
5407 if ((parent != NULL) &&
5408 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5409 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5410 parent->type = XML_RELAXNG_EMPTY;
5411 break;
5412 }
5413 if ((parent != NULL) &&
5414 ((parent->type == XML_RELAXNG_GROUP) ||
5415 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5416 (parent->type == XML_RELAXNG_CHOICE))) {
5417 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5418 } else
5419 prev = cur;
5420 } else {
5421 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005422 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005423 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005424 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005425 }
5426}
5427
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005428/**
5429 * xmlRelaxNGGroupContentType:
5430 * @ct1: the first content type
5431 * @ct2: the second content type
5432 *
5433 * Try to group 2 content types
5434 *
5435 * Returns the content type
5436 */
5437static xmlRelaxNGContentType
5438xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5439 xmlRelaxNGContentType ct2) {
5440 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5441 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5442 return(XML_RELAXNG_CONTENT_ERROR);
5443 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5444 return(ct2);
5445 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5446 return(ct1);
5447 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5448 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5449 return(XML_RELAXNG_CONTENT_COMPLEX);
5450 return(XML_RELAXNG_CONTENT_ERROR);
5451}
5452
5453/**
5454 * xmlRelaxNGMaxContentType:
5455 * @ct1: the first content type
5456 * @ct2: the second content type
5457 *
5458 * Compute the max content-type
5459 *
5460 * Returns the content type
5461 */
5462static xmlRelaxNGContentType
5463xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5464 xmlRelaxNGContentType ct2) {
5465 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5466 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5467 return(XML_RELAXNG_CONTENT_ERROR);
5468 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5469 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5470 return(XML_RELAXNG_CONTENT_SIMPLE);
5471 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5472 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5473 return(XML_RELAXNG_CONTENT_COMPLEX);
5474 return(XML_RELAXNG_CONTENT_EMPTY);
5475}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005476
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005477/**
5478 * xmlRelaxNGCheckRules:
5479 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005480 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005481 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005482 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005483 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005484 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005485 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005486 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005487 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005488static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005489xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5490 xmlRelaxNGDefinePtr cur, int flags,
5491 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005492 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005493 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005494
Daniel Veillardfd573f12003-03-16 17:52:32 +00005495 while (cur != NULL) {
5496 ret = XML_RELAXNG_CONTENT_EMPTY;
5497 if ((cur->type == XML_RELAXNG_REF) ||
5498 (cur->type == XML_RELAXNG_PARENTREF)) {
5499 if (flags & XML_RELAXNG_IN_LIST) {
5500 if (ctxt->error != NULL)
5501 ctxt->error(ctxt->userData,
5502 "Found forbidden pattern list//ref\n");
5503 ctxt->nbErrors++;
5504 }
5505 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5506 if (ctxt->error != NULL)
5507 ctxt->error(ctxt->userData,
5508 "Found forbidden pattern data/except//ref\n");
5509 ctxt->nbErrors++;
5510 }
5511 if (cur->depth > -4) {
5512 cur->depth = -4;
5513 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5514 flags, cur->type);
5515 cur->depth = ret - 15 ;
5516 } else if (cur->depth == -4) {
5517 ret = XML_RELAXNG_CONTENT_COMPLEX;
5518 } else {
5519 ret = (xmlRelaxNGContentType) cur->depth + 15;
5520 }
5521 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5522 /*
5523 * The 7.3 Attribute derivation rule for groups is plugged there
5524 */
5525 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5526 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5527 if (ctxt->error != NULL)
5528 ctxt->error(ctxt->userData,
5529 "Found forbidden pattern data/except//element(ref)\n");
5530 ctxt->nbErrors++;
5531 }
5532 if (flags & XML_RELAXNG_IN_LIST) {
5533 if (ctxt->error != NULL)
5534 ctxt->error(ctxt->userData,
5535 "Found forbidden pattern list//element(ref)\n");
5536 ctxt->nbErrors++;
5537 }
5538 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5539 if (ctxt->error != NULL)
5540 ctxt->error(ctxt->userData,
5541 "Found forbidden pattern attribute//element(ref)\n");
5542 ctxt->nbErrors++;
5543 }
5544 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5545 if (ctxt->error != NULL)
5546 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005547 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005548 ctxt->nbErrors++;
5549 }
5550 /*
5551 * reset since in the simple form elements are only child
5552 * of grammar/define
5553 */
5554 nflags = 0;
5555 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5556 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5557 if (ctxt->error != NULL)
5558 ctxt->error(ctxt->userData,
5559 "Element %s attributes have a content type error\n",
5560 cur->name);
5561 ctxt->nbErrors++;
5562 }
5563 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5564 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5565 if (ctxt->error != NULL)
5566 ctxt->error(ctxt->userData,
5567 "Element %s has a content type error\n",
5568 cur->name);
5569 ctxt->nbErrors++;
5570 } else {
5571 ret = XML_RELAXNG_CONTENT_COMPLEX;
5572 }
5573 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5574 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5575 if (ctxt->error != NULL)
5576 ctxt->error(ctxt->userData,
5577 "Found forbidden pattern attribute//attribute\n");
5578 ctxt->nbErrors++;
5579 }
5580 if (flags & XML_RELAXNG_IN_LIST) {
5581 if (ctxt->error != NULL)
5582 ctxt->error(ctxt->userData,
5583 "Found forbidden pattern list//attribute\n");
5584 ctxt->nbErrors++;
5585 }
5586 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5587 if (ctxt->error != NULL)
5588 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005589 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005590 ctxt->nbErrors++;
5591 }
5592 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5593 if (ctxt->error != NULL)
5594 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005595 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005596 ctxt->nbErrors++;
5597 }
5598 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5599 if (ctxt->error != NULL)
5600 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005601 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005602 ctxt->nbErrors++;
5603 }
5604 if (flags & XML_RELAXNG_IN_START) {
5605 if (ctxt->error != NULL)
5606 ctxt->error(ctxt->userData,
5607 "Found forbidden pattern start//attribute\n");
5608 ctxt->nbErrors++;
5609 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005610 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5611 if (cur->ns == NULL) {
5612 if (ctxt->error != NULL)
5613 ctxt->error(ctxt->userData,
5614 "Found anyName attribute without oneOrMore ancestor\n");
5615 ctxt->nbErrors++;
5616 } else {
5617 if (ctxt->error != NULL)
5618 ctxt->error(ctxt->userData,
5619 "Found nsName attribute without oneOrMore ancestor\n");
5620 ctxt->nbErrors++;
5621 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005622 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005623 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5624 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5625 ret = XML_RELAXNG_CONTENT_EMPTY;
5626 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5627 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5628 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5629 if (ctxt->error != NULL)
5630 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005631 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005632 ctxt->nbErrors++;
5633 }
5634 if (flags & XML_RELAXNG_IN_START) {
5635 if (ctxt->error != NULL)
5636 ctxt->error(ctxt->userData,
5637 "Found forbidden pattern start//oneOrMore\n");
5638 ctxt->nbErrors++;
5639 }
5640 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5641 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5642 ret = xmlRelaxNGGroupContentType(ret, ret);
5643 } else if (cur->type == XML_RELAXNG_LIST) {
5644 if (flags & XML_RELAXNG_IN_LIST) {
5645 if (ctxt->error != NULL)
5646 ctxt->error(ctxt->userData,
5647 "Found forbidden pattern list//list\n");
5648 ctxt->nbErrors++;
5649 }
5650 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5651 if (ctxt->error != NULL)
5652 ctxt->error(ctxt->userData,
5653 "Found forbidden pattern data/except//list\n");
5654 ctxt->nbErrors++;
5655 }
5656 if (flags & XML_RELAXNG_IN_START) {
5657 if (ctxt->error != NULL)
5658 ctxt->error(ctxt->userData,
5659 "Found forbidden pattern start//list\n");
5660 ctxt->nbErrors++;
5661 }
5662 nflags = flags | XML_RELAXNG_IN_LIST;
5663 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5664 } else if (cur->type == XML_RELAXNG_GROUP) {
5665 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5666 if (ctxt->error != NULL)
5667 ctxt->error(ctxt->userData,
5668 "Found forbidden pattern data/except//group\n");
5669 ctxt->nbErrors++;
5670 }
5671 if (flags & XML_RELAXNG_IN_START) {
5672 if (ctxt->error != NULL)
5673 ctxt->error(ctxt->userData,
5674 "Found forbidden pattern start//group\n");
5675 ctxt->nbErrors++;
5676 }
5677 if (flags & XML_RELAXNG_IN_ONEORMORE)
5678 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5679 else
5680 nflags = flags;
5681 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5682 /*
5683 * The 7.3 Attribute derivation rule for groups is plugged there
5684 */
5685 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5686 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5687 if (flags & XML_RELAXNG_IN_LIST) {
5688 if (ctxt->error != NULL)
5689 ctxt->error(ctxt->userData,
5690 "Found forbidden pattern list//interleave\n");
5691 ctxt->nbErrors++;
5692 }
5693 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5694 if (ctxt->error != NULL)
5695 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005696 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005697 ctxt->nbErrors++;
5698 }
5699 if (flags & XML_RELAXNG_IN_START) {
5700 if (ctxt->error != NULL)
5701 ctxt->error(ctxt->userData,
5702 "Found forbidden pattern start//interleave\n");
5703 ctxt->nbErrors++;
5704 }
5705 if (flags & XML_RELAXNG_IN_ONEORMORE)
5706 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5707 else
5708 nflags = flags;
5709 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5710 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5711 if ((cur->parent != NULL) &&
5712 (cur->parent->type == XML_RELAXNG_DATATYPE))
5713 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5714 else
5715 nflags = flags;
5716 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5717 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5718 if (flags & XML_RELAXNG_IN_START) {
5719 if (ctxt->error != NULL)
5720 ctxt->error(ctxt->userData,
5721 "Found forbidden pattern start//data\n");
5722 ctxt->nbErrors++;
5723 }
5724 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5725 ret = XML_RELAXNG_CONTENT_SIMPLE;
5726 } else if (cur->type == XML_RELAXNG_VALUE) {
5727 if (flags & XML_RELAXNG_IN_START) {
5728 if (ctxt->error != NULL)
5729 ctxt->error(ctxt->userData,
5730 "Found forbidden pattern start//value\n");
5731 ctxt->nbErrors++;
5732 }
5733 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5734 ret = XML_RELAXNG_CONTENT_SIMPLE;
5735 } else if (cur->type == XML_RELAXNG_TEXT) {
5736 if (flags & XML_RELAXNG_IN_LIST) {
5737 if (ctxt->error != NULL)
5738 ctxt->error(ctxt->userData,
5739 "Found forbidden pattern list//text\n");
5740 ctxt->nbErrors++;
5741 }
5742 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5743 if (ctxt->error != NULL)
5744 ctxt->error(ctxt->userData,
5745 "Found forbidden pattern data/except//text\n");
5746 ctxt->nbErrors++;
5747 }
5748 if (flags & XML_RELAXNG_IN_START) {
5749 if (ctxt->error != NULL)
5750 ctxt->error(ctxt->userData,
5751 "Found forbidden pattern start//text\n");
5752 ctxt->nbErrors++;
5753 }
5754 ret = XML_RELAXNG_CONTENT_COMPLEX;
5755 } else if (cur->type == XML_RELAXNG_EMPTY) {
5756 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5757 if (ctxt->error != NULL)
5758 ctxt->error(ctxt->userData,
5759 "Found forbidden pattern data/except//empty\n");
5760 ctxt->nbErrors++;
5761 }
5762 if (flags & XML_RELAXNG_IN_START) {
5763 if (ctxt->error != NULL)
5764 ctxt->error(ctxt->userData,
5765 "Found forbidden pattern start//empty\n");
5766 ctxt->nbErrors++;
5767 }
5768 ret = XML_RELAXNG_CONTENT_EMPTY;
5769 } else if (cur->type == XML_RELAXNG_CHOICE) {
5770 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5771 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5772 } else {
5773 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5774 }
5775 cur = cur->next;
5776 if (ptype == XML_RELAXNG_GROUP) {
5777 val = xmlRelaxNGGroupContentType(val, ret);
5778 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5779 tmp = xmlRelaxNGGroupContentType(val, ret);
5780 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5781 tmp = xmlRelaxNGMaxContentType(val, ret);
5782 } else if (ptype == XML_RELAXNG_CHOICE) {
5783 val = xmlRelaxNGMaxContentType(val, ret);
5784 } else if (ptype == XML_RELAXNG_LIST) {
5785 val = XML_RELAXNG_CONTENT_SIMPLE;
5786 } else if (ptype == XML_RELAXNG_EXCEPT) {
5787 if (ret == XML_RELAXNG_CONTENT_ERROR)
5788 val = XML_RELAXNG_CONTENT_ERROR;
5789 else
5790 val = XML_RELAXNG_CONTENT_SIMPLE;
5791 } else {
5792 val = xmlRelaxNGGroupContentType(val, ret);
5793 }
5794
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005795 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005796 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005797}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005798
5799/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005800 * xmlRelaxNGParseGrammar:
5801 * @ctxt: a Relax-NG parser context
5802 * @nodes: grammar children nodes
5803 *
5804 * parse a Relax-NG <grammar> node
5805 *
5806 * Returns the internal xmlRelaxNGGrammarPtr built or
5807 * NULL in case of error
5808 */
5809static xmlRelaxNGGrammarPtr
5810xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5811 xmlRelaxNGGrammarPtr ret, tmp, old;
5812
Daniel Veillardc482e262003-02-26 14:48:48 +00005813#ifdef DEBUG_GRAMMAR
5814 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5815#endif
5816
Daniel Veillard6eadf632003-01-23 18:29:16 +00005817 ret = xmlRelaxNGNewGrammar(ctxt);
5818 if (ret == NULL)
5819 return(NULL);
5820
5821 /*
5822 * Link the new grammar in the tree
5823 */
5824 ret->parent = ctxt->grammar;
5825 if (ctxt->grammar != NULL) {
5826 tmp = ctxt->grammar->children;
5827 if (tmp == NULL) {
5828 ctxt->grammar->children = ret;
5829 } else {
5830 while (tmp->next != NULL)
5831 tmp = tmp->next;
5832 tmp->next = ret;
5833 }
5834 }
5835
5836 old = ctxt->grammar;
5837 ctxt->grammar = ret;
5838 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5839 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005840 if (ctxt->grammar == NULL) {
5841 if (ctxt->error != NULL)
5842 ctxt->error(ctxt->userData,
5843 "Failed to parse <grammar> content\n");
5844 ctxt->nbErrors++;
5845 } else if (ctxt->grammar->start == NULL) {
5846 if (ctxt->error != NULL)
5847 ctxt->error(ctxt->userData,
5848 "Element <grammar> has no <start>\n");
5849 ctxt->nbErrors++;
5850 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005851
5852 /*
5853 * Apply 4.17 mergingd rules to defines and starts
5854 */
5855 xmlRelaxNGCombineStart(ctxt, ret);
5856 if (ret->defs != NULL) {
5857 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5858 ctxt);
5859 }
5860
5861 /*
5862 * link together defines and refs in this grammar
5863 */
5864 if (ret->refs != NULL) {
5865 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5866 ctxt);
5867 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005868
Daniel Veillard6eadf632003-01-23 18:29:16 +00005869 ctxt->grammar = old;
5870 return(ret);
5871}
5872
5873/**
5874 * xmlRelaxNGParseDocument:
5875 * @ctxt: a Relax-NG parser context
5876 * @node: the root node of the RelaxNG schema
5877 *
5878 * parse a Relax-NG definition resource and build an internal
5879 * xmlRelaxNG struture which can be used to validate instances.
5880 *
5881 * Returns the internal XML RelaxNG structure built or
5882 * NULL in case of error
5883 */
5884static xmlRelaxNGPtr
5885xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5886 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005887 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005888 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005889
5890 if ((ctxt == NULL) || (node == NULL))
5891 return (NULL);
5892
5893 schema = xmlRelaxNGNewRelaxNG(ctxt);
5894 if (schema == NULL)
5895 return(NULL);
5896
Daniel Veillard276be4a2003-01-24 01:03:34 +00005897 olddefine = ctxt->define;
5898 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005899 if (IS_RELAXNG(node, "grammar")) {
5900 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5901 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005902 xmlRelaxNGGrammarPtr tmp, ret;
5903
5904 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005905 if (schema->topgrammar == NULL) {
5906 return(schema);
5907 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005908 /*
5909 * Link the new grammar in the tree
5910 */
5911 ret->parent = ctxt->grammar;
5912 if (ctxt->grammar != NULL) {
5913 tmp = ctxt->grammar->children;
5914 if (tmp == NULL) {
5915 ctxt->grammar->children = ret;
5916 } else {
5917 while (tmp->next != NULL)
5918 tmp = tmp->next;
5919 tmp->next = ret;
5920 }
5921 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005922 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005923 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005924 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005925 if (old != NULL)
5926 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005927 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005928 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005929 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005930 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005931 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005932 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5933 while ((schema->topgrammar->start != NULL) &&
5934 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5935 (schema->topgrammar->start->next != NULL))
5936 schema->topgrammar->start = schema->topgrammar->start->content;
5937 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5938 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005939 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005940 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005941
5942#ifdef DEBUG
5943 if (schema == NULL)
5944 xmlGenericError(xmlGenericErrorContext,
5945 "xmlRelaxNGParseDocument() failed\n");
5946#endif
5947
5948 return (schema);
5949}
5950
5951/************************************************************************
5952 * *
5953 * Reading RelaxNGs *
5954 * *
5955 ************************************************************************/
5956
5957/**
5958 * xmlRelaxNGNewParserCtxt:
5959 * @URL: the location of the schema
5960 *
5961 * Create an XML RelaxNGs parse context for that file/resource expected
5962 * to contain an XML RelaxNGs file.
5963 *
5964 * Returns the parser context or NULL in case of error
5965 */
5966xmlRelaxNGParserCtxtPtr
5967xmlRelaxNGNewParserCtxt(const char *URL) {
5968 xmlRelaxNGParserCtxtPtr ret;
5969
5970 if (URL == NULL)
5971 return(NULL);
5972
5973 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5974 if (ret == NULL) {
5975 xmlGenericError(xmlGenericErrorContext,
5976 "Failed to allocate new schama parser context for %s\n", URL);
5977 return (NULL);
5978 }
5979 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5980 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005981 ret->error = xmlGenericError;
5982 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005983 return (ret);
5984}
5985
5986/**
5987 * xmlRelaxNGNewMemParserCtxt:
5988 * @buffer: a pointer to a char array containing the schemas
5989 * @size: the size of the array
5990 *
5991 * Create an XML RelaxNGs parse context for that memory buffer expected
5992 * to contain an XML RelaxNGs file.
5993 *
5994 * Returns the parser context or NULL in case of error
5995 */
5996xmlRelaxNGParserCtxtPtr
5997xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5998 xmlRelaxNGParserCtxtPtr ret;
5999
6000 if ((buffer == NULL) || (size <= 0))
6001 return(NULL);
6002
6003 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6004 if (ret == NULL) {
6005 xmlGenericError(xmlGenericErrorContext,
6006 "Failed to allocate new schama parser context\n");
6007 return (NULL);
6008 }
6009 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6010 ret->buffer = buffer;
6011 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006012 ret->error = xmlGenericError;
6013 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006014 return (ret);
6015}
6016
6017/**
6018 * xmlRelaxNGFreeParserCtxt:
6019 * @ctxt: the schema parser context
6020 *
6021 * Free the resources associated to the schema parser context
6022 */
6023void
6024xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6025 if (ctxt == NULL)
6026 return;
6027 if (ctxt->URL != NULL)
6028 xmlFree(ctxt->URL);
6029 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006030 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006031 if (ctxt->interleaves != NULL)
6032 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006033 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006034 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006035 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006036 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006037 if (ctxt->docTab != NULL)
6038 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006039 if (ctxt->incTab != NULL)
6040 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006041 if (ctxt->defTab != NULL) {
6042 int i;
6043
6044 for (i = 0;i < ctxt->defNr;i++)
6045 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6046 xmlFree(ctxt->defTab);
6047 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006048 xmlFree(ctxt);
6049}
6050
Daniel Veillard6eadf632003-01-23 18:29:16 +00006051/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006052 * xmlRelaxNGNormExtSpace:
6053 * @value: a value
6054 *
6055 * Removes the leading and ending spaces of the value
6056 * The string is modified "in situ"
6057 */
6058static void
6059xmlRelaxNGNormExtSpace(xmlChar *value) {
6060 xmlChar *start = value;
6061 xmlChar *cur = value;
6062 if (value == NULL)
6063 return;
6064
6065 while (IS_BLANK(*cur)) cur++;
6066 if (cur == start) {
6067 do {
6068 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6069 if (*cur == 0)
6070 return;
6071 start = cur;
6072 while (IS_BLANK(*cur)) cur++;
6073 if (*cur == 0) {
6074 *start = 0;
6075 return;
6076 }
6077 } while (1);
6078 } else {
6079 do {
6080 while ((*cur != 0) && (!IS_BLANK(*cur)))
6081 *start++ = *cur++;
6082 if (*cur == 0) {
6083 *start = 0;
6084 return;
6085 }
6086 /* don't try to normalize the inner spaces */
6087 while (IS_BLANK(*cur)) cur++;
6088 *start++ = *cur++;
6089 if (*cur == 0) {
6090 *start = 0;
6091 return;
6092 }
6093 } while (1);
6094 }
6095}
6096
6097/**
6098 * xmlRelaxNGCheckAttributes:
6099 * @ctxt: a Relax-NG parser context
6100 * @node: a Relax-NG node
6101 *
6102 * Check all the attributes on the given node
6103 */
6104static void
6105xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6106 xmlAttrPtr cur, next;
6107
6108 cur = node->properties;
6109 while (cur != NULL) {
6110 next = cur->next;
6111 if ((cur->ns == NULL) ||
6112 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6113 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6114 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6115 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6116 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6117 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006118 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006119 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6120 if (ctxt->error != NULL)
6121 ctxt->error(ctxt->userData,
6122 "Attribute %s is not allowed on %s\n",
6123 cur->name, node->name);
6124 ctxt->nbErrors++;
6125 }
6126 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6127 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6128 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6129 if (ctxt->error != NULL)
6130 ctxt->error(ctxt->userData,
6131 "Attribute %s is not allowed on %s\n",
6132 cur->name, node->name);
6133 ctxt->nbErrors++;
6134 }
6135 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6136 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6137 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6138 if (ctxt->error != NULL)
6139 ctxt->error(ctxt->userData,
6140 "Attribute %s is not allowed on %s\n",
6141 cur->name, node->name);
6142 ctxt->nbErrors++;
6143 }
6144 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6145 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6146 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6147 if (ctxt->error != NULL)
6148 ctxt->error(ctxt->userData,
6149 "Attribute %s is not allowed on %s\n",
6150 cur->name, node->name);
6151 ctxt->nbErrors++;
6152 }
6153 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6154 xmlChar *val;
6155 xmlURIPtr uri;
6156
6157 val = xmlNodeListGetString(node->doc, cur->children, 1);
6158 if (val != NULL) {
6159 if (val[0] != 0) {
6160 uri = xmlParseURI((const char *) val);
6161 if (uri == NULL) {
6162 if (ctxt->error != NULL)
6163 ctxt->error(ctxt->userData,
6164 "Attribute %s contains invalid URI %s\n",
6165 cur->name, val);
6166 ctxt->nbErrors++;
6167 } else {
6168 if (uri->scheme == NULL) {
6169 if (ctxt->error != NULL)
6170 ctxt->error(ctxt->userData,
6171 "Attribute %s URI %s is not absolute\n",
6172 cur->name, val);
6173 ctxt->nbErrors++;
6174 }
6175 if (uri->fragment != NULL) {
6176 if (ctxt->error != NULL)
6177 ctxt->error(ctxt->userData,
6178 "Attribute %s URI %s has a fragment ID\n",
6179 cur->name, val);
6180 ctxt->nbErrors++;
6181 }
6182 xmlFreeURI(uri);
6183 }
6184 }
6185 xmlFree(val);
6186 }
6187 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6188 if (ctxt->error != NULL)
6189 ctxt->error(ctxt->userData,
6190 "Unknown attribute %s on %s\n",
6191 cur->name, node->name);
6192 ctxt->nbErrors++;
6193 }
6194 }
6195 cur = next;
6196 }
6197}
6198
6199/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006200 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006201 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006202 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006203 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006204 * Cleanup the subtree from unwanted nodes for parsing, resolve
6205 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006206 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006207static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006208xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006209 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006210
Daniel Veillard6eadf632003-01-23 18:29:16 +00006211 delete = NULL;
6212 cur = root;
6213 while (cur != NULL) {
6214 if (delete != NULL) {
6215 xmlUnlinkNode(delete);
6216 xmlFreeNode(delete);
6217 delete = NULL;
6218 }
6219 if (cur->type == XML_ELEMENT_NODE) {
6220 /*
6221 * Simplification 4.1. Annotations
6222 */
6223 if ((cur->ns == NULL) ||
6224 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006225 if ((cur->parent != NULL) &&
6226 (cur->parent->type == XML_ELEMENT_NODE) &&
6227 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6228 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6229 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6230 if (ctxt->error != NULL)
6231 ctxt->error(ctxt->userData,
6232 "element %s doesn't allow foreign elements\n",
6233 cur->parent->name);
6234 ctxt->nbErrors++;
6235 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006236 delete = cur;
6237 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006238 } else {
6239 xmlRelaxNGCleanupAttributes(ctxt, cur);
6240 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6241 xmlChar *href, *ns, *base, *URL;
6242 xmlRelaxNGDocumentPtr docu;
6243 xmlNodePtr tmp;
6244
6245 ns = xmlGetProp(cur, BAD_CAST "ns");
6246 if (ns == NULL) {
6247 tmp = cur->parent;
6248 while ((tmp != NULL) &&
6249 (tmp->type == XML_ELEMENT_NODE)) {
6250 ns = xmlGetProp(tmp, BAD_CAST "ns");
6251 if (ns != NULL)
6252 break;
6253 tmp = tmp->parent;
6254 }
6255 }
6256 href = xmlGetProp(cur, BAD_CAST "href");
6257 if (href == NULL) {
6258 if (ctxt->error != NULL)
6259 ctxt->error(ctxt->userData,
6260 "xmlRelaxNGParse: externalRef has no href attribute\n");
6261 ctxt->nbErrors++;
6262 delete = cur;
6263 goto skip_children;
6264 }
6265 base = xmlNodeGetBase(cur->doc, cur);
6266 URL = xmlBuildURI(href, base);
6267 if (URL == NULL) {
6268 if (ctxt->error != NULL)
6269 ctxt->error(ctxt->userData,
6270 "Failed to compute URL for externalRef %s\n", href);
6271 ctxt->nbErrors++;
6272 if (href != NULL)
6273 xmlFree(href);
6274 if (base != NULL)
6275 xmlFree(base);
6276 delete = cur;
6277 goto skip_children;
6278 }
6279 if (href != NULL)
6280 xmlFree(href);
6281 if (base != NULL)
6282 xmlFree(base);
6283 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6284 if (docu == NULL) {
6285 if (ctxt->error != NULL)
6286 ctxt->error(ctxt->userData,
6287 "Failed to load externalRef %s\n", URL);
6288 ctxt->nbErrors++;
6289 xmlFree(URL);
6290 delete = cur;
6291 goto skip_children;
6292 }
6293 if (ns != NULL)
6294 xmlFree(ns);
6295 xmlFree(URL);
6296 cur->_private = docu;
6297 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6298 xmlChar *href, *ns, *base, *URL;
6299 xmlRelaxNGIncludePtr incl;
6300 xmlNodePtr tmp;
6301
6302 href = xmlGetProp(cur, BAD_CAST "href");
6303 if (href == NULL) {
6304 if (ctxt->error != NULL)
6305 ctxt->error(ctxt->userData,
6306 "xmlRelaxNGParse: include has no href attribute\n");
6307 ctxt->nbErrors++;
6308 delete = cur;
6309 goto skip_children;
6310 }
6311 base = xmlNodeGetBase(cur->doc, cur);
6312 URL = xmlBuildURI(href, base);
6313 if (URL == NULL) {
6314 if (ctxt->error != NULL)
6315 ctxt->error(ctxt->userData,
6316 "Failed to compute URL for include %s\n", href);
6317 ctxt->nbErrors++;
6318 if (href != NULL)
6319 xmlFree(href);
6320 if (base != NULL)
6321 xmlFree(base);
6322 delete = cur;
6323 goto skip_children;
6324 }
6325 if (href != NULL)
6326 xmlFree(href);
6327 if (base != NULL)
6328 xmlFree(base);
6329 ns = xmlGetProp(cur, BAD_CAST "ns");
6330 if (ns == NULL) {
6331 tmp = cur->parent;
6332 while ((tmp != NULL) &&
6333 (tmp->type == XML_ELEMENT_NODE)) {
6334 ns = xmlGetProp(tmp, BAD_CAST "ns");
6335 if (ns != NULL)
6336 break;
6337 tmp = tmp->parent;
6338 }
6339 }
6340 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6341 if (ns != NULL)
6342 xmlFree(ns);
6343 if (incl == NULL) {
6344 if (ctxt->error != NULL)
6345 ctxt->error(ctxt->userData,
6346 "Failed to load include %s\n", URL);
6347 ctxt->nbErrors++;
6348 xmlFree(URL);
6349 delete = cur;
6350 goto skip_children;
6351 }
6352 xmlFree(URL);
6353 cur->_private = incl;
6354 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6355 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6356 xmlChar *name, *ns;
6357 xmlNodePtr text = NULL;
6358
6359 /*
6360 * Simplification 4.8. name attribute of element
6361 * and attribute elements
6362 */
6363 name = xmlGetProp(cur, BAD_CAST "name");
6364 if (name != NULL) {
6365 if (cur->children == NULL) {
6366 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6367 name);
6368 } else {
6369 xmlNodePtr node;
6370 node = xmlNewNode(cur->ns, BAD_CAST "name");
6371 if (node != NULL) {
6372 xmlAddPrevSibling(cur->children, node);
6373 text = xmlNewText(name);
6374 xmlAddChild(node, text);
6375 text = node;
6376 }
6377 }
6378 if (text == NULL) {
6379 if (ctxt->error != NULL)
6380 ctxt->error(ctxt->userData,
6381 "Failed to create a name %s element\n", name);
6382 ctxt->nbErrors++;
6383 }
6384 xmlUnsetProp(cur, BAD_CAST "name");
6385 xmlFree(name);
6386 ns = xmlGetProp(cur, BAD_CAST "ns");
6387 if (ns != NULL) {
6388 if (text != NULL) {
6389 xmlSetProp(text, BAD_CAST "ns", ns);
6390 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6391 }
6392 xmlFree(ns);
6393 } else if (xmlStrEqual(cur->name,
6394 BAD_CAST "attribute")) {
6395 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6396 }
6397 }
6398 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6399 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6400 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6401 /*
6402 * Simplification 4.8. name attribute of element
6403 * and attribute elements
6404 */
6405 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6406 xmlNodePtr node;
6407 xmlChar *ns = NULL;
6408
6409 node = cur->parent;
6410 while ((node != NULL) &&
6411 (node->type == XML_ELEMENT_NODE)) {
6412 ns = xmlGetProp(node, BAD_CAST "ns");
6413 if (ns != NULL) {
6414 break;
6415 }
6416 node = node->parent;
6417 }
6418 if (ns == NULL) {
6419 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6420 } else {
6421 xmlSetProp(cur, BAD_CAST "ns", ns);
6422 xmlFree(ns);
6423 }
6424 }
6425 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6426 xmlChar *name, *local, *prefix;
6427
6428 /*
6429 * Simplification: 4.10. QNames
6430 */
6431 name = xmlNodeGetContent(cur);
6432 if (name != NULL) {
6433 local = xmlSplitQName2(name, &prefix);
6434 if (local != NULL) {
6435 xmlNsPtr ns;
6436
6437 ns = xmlSearchNs(cur->doc, cur, prefix);
6438 if (ns == NULL) {
6439 if (ctxt->error != NULL)
6440 ctxt->error(ctxt->userData,
6441 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6442 ctxt->nbErrors++;
6443 } else {
6444 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6445 xmlNodeSetContent(cur, local);
6446 }
6447 xmlFree(local);
6448 xmlFree(prefix);
6449 }
6450 xmlFree(name);
6451 }
6452 }
6453 /*
6454 * 4.16
6455 */
6456 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6457 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6458 if (ctxt->error != NULL)
6459 ctxt->error(ctxt->userData,
6460 "Found nsName/except//nsName forbidden construct\n");
6461 ctxt->nbErrors++;
6462 }
6463 }
6464 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6465 (cur != root)) {
6466 int oldflags = ctxt->flags;
6467
6468 /*
6469 * 4.16
6470 */
6471 if ((cur->parent != NULL) &&
6472 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6473 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6474 xmlRelaxNGCleanupTree(ctxt, cur);
6475 ctxt->flags = oldflags;
6476 goto skip_children;
6477 } else if ((cur->parent != NULL) &&
6478 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6479 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6480 xmlRelaxNGCleanupTree(ctxt, cur);
6481 ctxt->flags = oldflags;
6482 goto skip_children;
6483 }
6484 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6485 /*
6486 * 4.16
6487 */
6488 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6489 if (ctxt->error != NULL)
6490 ctxt->error(ctxt->userData,
6491 "Found anyName/except//anyName forbidden construct\n");
6492 ctxt->nbErrors++;
6493 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6494 if (ctxt->error != NULL)
6495 ctxt->error(ctxt->userData,
6496 "Found nsName/except//anyName forbidden construct\n");
6497 ctxt->nbErrors++;
6498 }
6499 }
6500 /*
6501 * Thisd is not an else since "include" is transformed
6502 * into a div
6503 */
6504 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6505 xmlChar *ns;
6506 xmlNodePtr child, ins, tmp;
6507
6508 /*
6509 * implements rule 4.11
6510 */
6511
6512 ns = xmlGetProp(cur, BAD_CAST "ns");
6513
6514 child = cur->children;
6515 ins = cur;
6516 while (child != NULL) {
6517 if (ns != NULL) {
6518 if (!xmlHasProp(child, BAD_CAST "ns")) {
6519 xmlSetProp(child, BAD_CAST "ns", ns);
6520 }
6521 }
6522 tmp = child->next;
6523 xmlUnlinkNode(child);
6524 ins = xmlAddNextSibling(ins, child);
6525 child = tmp;
6526 }
6527 if (ns != NULL)
6528 xmlFree(ns);
6529 delete = cur;
6530 goto skip_children;
6531 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006532 }
6533 }
6534 /*
6535 * Simplification 4.2 whitespaces
6536 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006537 else if ((cur->type == XML_TEXT_NODE) ||
6538 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006539 if (IS_BLANK_NODE(cur)) {
6540 if (cur->parent->type == XML_ELEMENT_NODE) {
6541 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6542 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6543 delete = cur;
6544 } else {
6545 delete = cur;
6546 goto skip_children;
6547 }
6548 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006549 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006550 delete = cur;
6551 goto skip_children;
6552 }
6553
6554 /*
6555 * Skip to next node
6556 */
6557 if (cur->children != NULL) {
6558 if ((cur->children->type != XML_ENTITY_DECL) &&
6559 (cur->children->type != XML_ENTITY_REF_NODE) &&
6560 (cur->children->type != XML_ENTITY_NODE)) {
6561 cur = cur->children;
6562 continue;
6563 }
6564 }
6565skip_children:
6566 if (cur->next != NULL) {
6567 cur = cur->next;
6568 continue;
6569 }
6570
6571 do {
6572 cur = cur->parent;
6573 if (cur == NULL)
6574 break;
6575 if (cur == root) {
6576 cur = NULL;
6577 break;
6578 }
6579 if (cur->next != NULL) {
6580 cur = cur->next;
6581 break;
6582 }
6583 } while (cur != NULL);
6584 }
6585 if (delete != NULL) {
6586 xmlUnlinkNode(delete);
6587 xmlFreeNode(delete);
6588 delete = NULL;
6589 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006590}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006591
Daniel Veillardc5312d72003-02-21 17:14:10 +00006592/**
6593 * xmlRelaxNGCleanupDoc:
6594 * @ctxt: a Relax-NG parser context
6595 * @doc: an xmldocPtr document pointer
6596 *
6597 * Cleanup the document from unwanted nodes for parsing, resolve
6598 * Include and externalRef lookups.
6599 *
6600 * Returns the cleaned up document or NULL in case of error
6601 */
6602static xmlDocPtr
6603xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6604 xmlNodePtr root;
6605
6606 /*
6607 * Extract the root
6608 */
6609 root = xmlDocGetRootElement(doc);
6610 if (root == NULL) {
6611 if (ctxt->error != NULL)
6612 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6613 ctxt->URL);
6614 ctxt->nbErrors++;
6615 return (NULL);
6616 }
6617 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006618 return(doc);
6619}
6620
6621/**
6622 * xmlRelaxNGParse:
6623 * @ctxt: a Relax-NG parser context
6624 *
6625 * parse a schema definition resource and build an internal
6626 * XML Shema struture which can be used to validate instances.
6627 * *WARNING* this interface is highly subject to change
6628 *
6629 * Returns the internal XML RelaxNG structure built from the resource or
6630 * NULL in case of error
6631 */
6632xmlRelaxNGPtr
6633xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6634{
6635 xmlRelaxNGPtr ret = NULL;
6636 xmlDocPtr doc;
6637 xmlNodePtr root;
6638
6639 xmlRelaxNGInitTypes();
6640
6641 if (ctxt == NULL)
6642 return (NULL);
6643
6644 /*
6645 * First step is to parse the input document into an DOM/Infoset
6646 */
6647 if (ctxt->URL != NULL) {
6648 doc = xmlParseFile((const char *) ctxt->URL);
6649 if (doc == NULL) {
6650 if (ctxt->error != NULL)
6651 ctxt->error(ctxt->userData,
6652 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6653 ctxt->nbErrors++;
6654 return (NULL);
6655 }
6656 } else if (ctxt->buffer != NULL) {
6657 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6658 if (doc == NULL) {
6659 if (ctxt->error != NULL)
6660 ctxt->error(ctxt->userData,
6661 "xmlRelaxNGParse: could not parse schemas\n");
6662 ctxt->nbErrors++;
6663 return (NULL);
6664 }
6665 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6666 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6667 } else {
6668 if (ctxt->error != NULL)
6669 ctxt->error(ctxt->userData,
6670 "xmlRelaxNGParse: nothing to parse\n");
6671 ctxt->nbErrors++;
6672 return (NULL);
6673 }
6674 ctxt->document = doc;
6675
6676 /*
6677 * Some preprocessing of the document content
6678 */
6679 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6680 if (doc == NULL) {
6681 xmlFreeDoc(ctxt->document);
6682 ctxt->document = NULL;
6683 return(NULL);
6684 }
6685
Daniel Veillard6eadf632003-01-23 18:29:16 +00006686 /*
6687 * Then do the parsing for good
6688 */
6689 root = xmlDocGetRootElement(doc);
6690 if (root == NULL) {
6691 if (ctxt->error != NULL)
6692 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6693 ctxt->URL);
6694 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006695 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006696 return (NULL);
6697 }
6698 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006699 if (ret == NULL) {
6700 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006701 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006702 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006703
6704 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006705 * Check the ref/defines links
6706 */
6707 /*
6708 * try to preprocess interleaves
6709 */
6710 if (ctxt->interleaves != NULL) {
6711 xmlHashScan(ctxt->interleaves,
6712 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6713 }
6714
6715 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006716 * if there was a parsing error return NULL
6717 */
6718 if (ctxt->nbErrors > 0) {
6719 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006720 ctxt->document = NULL;
6721 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006722 return(NULL);
6723 }
6724
6725 /*
6726 * Transfer the pointer for cleanup at the schema level.
6727 */
6728 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006729 ctxt->document = NULL;
6730 ret->documents = ctxt->documents;
6731 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006732
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006733 ret->includes = ctxt->includes;
6734 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006735 ret->defNr = ctxt->defNr;
6736 ret->defTab = ctxt->defTab;
6737 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006738 if (ctxt->idref == 1)
6739 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006740
6741 return (ret);
6742}
6743
6744/**
6745 * xmlRelaxNGSetParserErrors:
6746 * @ctxt: a Relax-NG validation context
6747 * @err: the error callback
6748 * @warn: the warning callback
6749 * @ctx: contextual data for the callbacks
6750 *
6751 * Set the callback functions used to handle errors for a validation context
6752 */
6753void
6754xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6755 xmlRelaxNGValidityErrorFunc err,
6756 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6757 if (ctxt == NULL)
6758 return;
6759 ctxt->error = err;
6760 ctxt->warning = warn;
6761 ctxt->userData = ctx;
6762}
6763/************************************************************************
6764 * *
6765 * Dump back a compiled form *
6766 * *
6767 ************************************************************************/
6768static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6769
6770/**
6771 * xmlRelaxNGDumpDefines:
6772 * @output: the file output
6773 * @defines: a list of define structures
6774 *
6775 * Dump a RelaxNG structure back
6776 */
6777static void
6778xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6779 while (defines != NULL) {
6780 xmlRelaxNGDumpDefine(output, defines);
6781 defines = defines->next;
6782 }
6783}
6784
6785/**
6786 * xmlRelaxNGDumpDefine:
6787 * @output: the file output
6788 * @define: a define structure
6789 *
6790 * Dump a RelaxNG structure back
6791 */
6792static void
6793xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6794 if (define == NULL)
6795 return;
6796 switch(define->type) {
6797 case XML_RELAXNG_EMPTY:
6798 fprintf(output, "<empty/>\n");
6799 break;
6800 case XML_RELAXNG_NOT_ALLOWED:
6801 fprintf(output, "<notAllowed/>\n");
6802 break;
6803 case XML_RELAXNG_TEXT:
6804 fprintf(output, "<text/>\n");
6805 break;
6806 case XML_RELAXNG_ELEMENT:
6807 fprintf(output, "<element>\n");
6808 if (define->name != NULL) {
6809 fprintf(output, "<name");
6810 if (define->ns != NULL)
6811 fprintf(output, " ns=\"%s\"", define->ns);
6812 fprintf(output, ">%s</name>\n", define->name);
6813 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006814 xmlRelaxNGDumpDefines(output, define->attrs);
6815 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006816 fprintf(output, "</element>\n");
6817 break;
6818 case XML_RELAXNG_LIST:
6819 fprintf(output, "<list>\n");
6820 xmlRelaxNGDumpDefines(output, define->content);
6821 fprintf(output, "</list>\n");
6822 break;
6823 case XML_RELAXNG_ONEORMORE:
6824 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006825 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006826 fprintf(output, "</oneOrMore>\n");
6827 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006828 case XML_RELAXNG_ZEROORMORE:
6829 fprintf(output, "<zeroOrMore>\n");
6830 xmlRelaxNGDumpDefines(output, define->content);
6831 fprintf(output, "</zeroOrMore>\n");
6832 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006833 case XML_RELAXNG_CHOICE:
6834 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006835 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006836 fprintf(output, "</choice>\n");
6837 break;
6838 case XML_RELAXNG_GROUP:
6839 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006840 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006841 fprintf(output, "</group>\n");
6842 break;
6843 case XML_RELAXNG_INTERLEAVE:
6844 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006845 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006846 fprintf(output, "</interleave>\n");
6847 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006848 case XML_RELAXNG_OPTIONAL:
6849 fprintf(output, "<optional>\n");
6850 xmlRelaxNGDumpDefines(output, define->content);
6851 fprintf(output, "</optional>\n");
6852 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006853 case XML_RELAXNG_ATTRIBUTE:
6854 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006855 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006856 fprintf(output, "</attribute>\n");
6857 break;
6858 case XML_RELAXNG_DEF:
6859 fprintf(output, "<define");
6860 if (define->name != NULL)
6861 fprintf(output, " name=\"%s\"", define->name);
6862 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006863 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006864 fprintf(output, "</define>\n");
6865 break;
6866 case XML_RELAXNG_REF:
6867 fprintf(output, "<ref");
6868 if (define->name != NULL)
6869 fprintf(output, " name=\"%s\"", define->name);
6870 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006871 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006872 fprintf(output, "</ref>\n");
6873 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006874 case XML_RELAXNG_PARENTREF:
6875 fprintf(output, "<parentRef");
6876 if (define->name != NULL)
6877 fprintf(output, " name=\"%s\"", define->name);
6878 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006879 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006880 fprintf(output, "</parentRef>\n");
6881 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006882 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006883 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006884 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006885 fprintf(output, "</externalRef>\n");
6886 break;
6887 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006888 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006889 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006890 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006891 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006892 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006893 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006894 TODO
6895 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006896 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006897 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006898 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006899 }
6900}
6901
6902/**
6903 * xmlRelaxNGDumpGrammar:
6904 * @output: the file output
6905 * @grammar: a grammar structure
6906 * @top: is this a top grammar
6907 *
6908 * Dump a RelaxNG structure back
6909 */
6910static void
6911xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6912{
6913 if (grammar == NULL)
6914 return;
6915
6916 fprintf(output, "<grammar");
6917 if (top)
6918 fprintf(output,
6919 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6920 switch(grammar->combine) {
6921 case XML_RELAXNG_COMBINE_UNDEFINED:
6922 break;
6923 case XML_RELAXNG_COMBINE_CHOICE:
6924 fprintf(output, " combine=\"choice\"");
6925 break;
6926 case XML_RELAXNG_COMBINE_INTERLEAVE:
6927 fprintf(output, " combine=\"interleave\"");
6928 break;
6929 default:
6930 fprintf(output, " <!-- invalid combine value -->");
6931 }
6932 fprintf(output, ">\n");
6933 if (grammar->start == NULL) {
6934 fprintf(output, " <!-- grammar had no start -->");
6935 } else {
6936 fprintf(output, "<start>\n");
6937 xmlRelaxNGDumpDefine(output, grammar->start);
6938 fprintf(output, "</start>\n");
6939 }
6940 /* TODO ? Dump the defines ? */
6941 fprintf(output, "</grammar>\n");
6942}
6943
6944/**
6945 * xmlRelaxNGDump:
6946 * @output: the file output
6947 * @schema: a schema structure
6948 *
6949 * Dump a RelaxNG structure back
6950 */
6951void
6952xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6953{
6954 if (schema == NULL) {
6955 fprintf(output, "RelaxNG empty or failed to compile\n");
6956 return;
6957 }
6958 fprintf(output, "RelaxNG: ");
6959 if (schema->doc == NULL) {
6960 fprintf(output, "no document\n");
6961 } else if (schema->doc->URL != NULL) {
6962 fprintf(output, "%s\n", schema->doc->URL);
6963 } else {
6964 fprintf(output, "\n");
6965 }
6966 if (schema->topgrammar == NULL) {
6967 fprintf(output, "RelaxNG has no top grammar\n");
6968 return;
6969 }
6970 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6971}
6972
Daniel Veillardfebcca42003-02-16 15:44:18 +00006973/**
6974 * xmlRelaxNGDumpTree:
6975 * @output: the file output
6976 * @schema: a schema structure
6977 *
6978 * Dump the transformed RelaxNG tree.
6979 */
6980void
6981xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6982{
6983 if (schema == NULL) {
6984 fprintf(output, "RelaxNG empty or failed to compile\n");
6985 return;
6986 }
6987 if (schema->doc == NULL) {
6988 fprintf(output, "no document\n");
6989 } else {
6990 xmlDocDump(output, schema->doc);
6991 }
6992}
6993
Daniel Veillard6eadf632003-01-23 18:29:16 +00006994/************************************************************************
6995 * *
6996 * Validation implementation *
6997 * *
6998 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006999static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7000 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007001static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7002 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007003
7004/**
7005 * xmlRelaxNGSkipIgnored:
7006 * @ctxt: a schema validation context
7007 * @node: the top node.
7008 *
7009 * Skip ignorable nodes in that context
7010 *
7011 * Returns the new sibling or NULL in case of error.
7012 */
7013static xmlNodePtr
7014xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7015 xmlNodePtr node) {
7016 /*
7017 * TODO complete and handle entities
7018 */
7019 while ((node != NULL) &&
7020 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007021 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007022 (((node->type == XML_TEXT_NODE) ||
7023 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007024 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
7025 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007026 node = node->next;
7027 }
7028 return(node);
7029}
7030
7031/**
Daniel Veillardedc91922003-01-26 00:52:04 +00007032 * xmlRelaxNGNormalize:
7033 * @ctxt: a schema validation context
7034 * @str: the string to normalize
7035 *
7036 * Implements the normalizeWhiteSpace( s ) function from
7037 * section 6.2.9 of the spec
7038 *
7039 * Returns the new string or NULL in case of error.
7040 */
7041static xmlChar *
7042xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
7043 xmlChar *ret, *p;
7044 const xmlChar *tmp;
7045 int len;
7046
7047 if (str == NULL)
7048 return(NULL);
7049 tmp = str;
7050 while (*tmp != 0) tmp++;
7051 len = tmp - str;
7052
7053 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7054 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007055 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007056 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007057 } else {
7058 xmlGenericError(xmlGenericErrorContext,
7059 "xmlRelaxNGNormalize: out of memory\n");
7060 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007061 return(NULL);
7062 }
7063 p = ret;
7064 while (IS_BLANK(*str)) str++;
7065 while (*str != 0) {
7066 if (IS_BLANK(*str)) {
7067 while (IS_BLANK(*str)) str++;
7068 if (*str == 0)
7069 break;
7070 *p++ = ' ';
7071 } else
7072 *p++ = *str++;
7073 }
7074 *p = 0;
7075 return(ret);
7076}
7077
7078/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007079 * xmlRelaxNGValidateDatatype:
7080 * @ctxt: a Relax-NG validation context
7081 * @value: the string value
7082 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007083 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007084 *
7085 * Validate the given value against the dataype
7086 *
7087 * Returns 0 if the validation succeeded or an error code.
7088 */
7089static int
7090xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007091 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007092 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007093 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007094 void *result = NULL;
7095 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007096
7097 if ((define == NULL) || (define->data == NULL)) {
7098 return(-1);
7099 }
7100 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007101 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007102 if ((define->attrs != NULL) &&
7103 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007104 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007105 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007106 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007107 }
7108 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007109 ret = -1;
7110 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007111 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007112 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7113 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007114 return(-1);
7115 } else if (ret == 1) {
7116 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007117 } else if (ret == 2) {
7118 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007119 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007120 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007121 ret = -1;
7122 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007123 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007124 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7125 if (lib->facet != NULL) {
7126 tmp = lib->facet(lib->data, define->name, cur->name,
7127 cur->value, value, result);
7128 if (tmp != 0)
7129 ret = -1;
7130 }
7131 cur = cur->next;
7132 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007133 if ((ret == 0) && (define->content != NULL)) {
7134 const xmlChar *oldvalue, *oldendvalue;
7135
7136 oldvalue = ctxt->state->value;
7137 oldendvalue = ctxt->state->endvalue;
7138 ctxt->state->value = (xmlChar *) value;
7139 ctxt->state->endvalue = NULL;
7140 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7141 ctxt->state->value = (xmlChar *) oldvalue;
7142 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7143 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007144 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7145 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007146 return(ret);
7147}
7148
7149/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007150 * xmlRelaxNGNextValue:
7151 * @ctxt: a Relax-NG validation context
7152 *
7153 * Skip to the next value when validating within a list
7154 *
7155 * Returns 0 if the operation succeeded or an error code.
7156 */
7157static int
7158xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7159 xmlChar *cur;
7160
7161 cur = ctxt->state->value;
7162 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7163 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007164 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007165 return(0);
7166 }
7167 while (*cur != 0) cur++;
7168 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7169 if (cur == ctxt->state->endvalue)
7170 ctxt->state->value = NULL;
7171 else
7172 ctxt->state->value = cur;
7173 return(0);
7174}
7175
7176/**
7177 * xmlRelaxNGValidateValueList:
7178 * @ctxt: a Relax-NG validation context
7179 * @defines: the list of definitions to verify
7180 *
7181 * Validate the given set of definitions for the current value
7182 *
7183 * Returns 0 if the validation succeeded or an error code.
7184 */
7185static int
7186xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7187 xmlRelaxNGDefinePtr defines) {
7188 int ret = 0;
7189
7190 while (defines != NULL) {
7191 ret = xmlRelaxNGValidateValue(ctxt, defines);
7192 if (ret != 0)
7193 break;
7194 defines = defines->next;
7195 }
7196 return(ret);
7197}
7198
7199/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007200 * xmlRelaxNGValidateValue:
7201 * @ctxt: a Relax-NG validation context
7202 * @define: the definition to verify
7203 *
7204 * Validate the given definition for the current value
7205 *
7206 * Returns 0 if the validation succeeded or an error code.
7207 */
7208static int
7209xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7210 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007211 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007212 xmlChar *value;
7213
7214 value = ctxt->state->value;
7215 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007216 case XML_RELAXNG_EMPTY: {
7217 if ((value != NULL) && (value[0] != 0)) {
7218 int idx = 0;
7219
7220 while (IS_BLANK(value[idx]))
7221 idx++;
7222 if (value[idx] != 0)
7223 ret = -1;
7224 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007225 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007226 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007227 case XML_RELAXNG_TEXT:
7228 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007229 case XML_RELAXNG_VALUE: {
7230 if (!xmlStrEqual(value, define->value)) {
7231 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007232 xmlRelaxNGTypeLibraryPtr lib;
7233
7234 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
7235 if ((lib != NULL) && (lib->comp != NULL))
7236 ret = lib->comp(lib->data, define->name, value,
7237 define->value);
7238 else
7239 ret = -1;
7240 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007241 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007242 return(-1);
7243 } else if (ret == 1) {
7244 ret = 0;
7245 } else {
7246 ret = -1;
7247 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007248 } else {
7249 xmlChar *nval, *nvalue;
7250
7251 /*
7252 * TODO: trivial optimizations are possible by
7253 * computing at compile-time
7254 */
7255 nval = xmlRelaxNGNormalize(ctxt, define->value);
7256 nvalue = xmlRelaxNGNormalize(ctxt, value);
7257
Daniel Veillardea3f3982003-01-26 19:45:18 +00007258 if ((nval == NULL) || (nvalue == NULL) ||
7259 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007260 ret = -1;
7261 if (nval != NULL)
7262 xmlFree(nval);
7263 if (nvalue != NULL)
7264 xmlFree(nvalue);
7265 }
7266 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007267 if (ret == 0)
7268 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007269 break;
7270 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007271 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007272 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7273 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007274 if (ret == 0)
7275 xmlRelaxNGNextValue(ctxt);
7276
7277 break;
7278 }
7279 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007280 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007281 xmlChar *oldvalue;
7282
7283 oldflags = ctxt->flags;
7284 ctxt->flags |= FLAGS_IGNORABLE;
7285
7286 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007287 while (list != NULL) {
7288 ret = xmlRelaxNGValidateValue(ctxt, list);
7289 if (ret == 0) {
7290 break;
7291 }
7292 ctxt->state->value = oldvalue;
7293 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007294 }
7295 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007296 if (ret != 0) {
7297 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7298 xmlRelaxNGDumpValidError(ctxt);
7299 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007300 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007301 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007302 if (ret == 0)
7303 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007304 break;
7305 }
7306 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007307 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007308 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007309#ifdef DEBUG_LIST
7310 int nb_values = 0;
7311#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007312
7313 oldvalue = ctxt->state->value;
7314 oldend = ctxt->state->endvalue;
7315
7316 val = xmlStrdup(oldvalue);
7317 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007318 val = xmlStrdup(BAD_CAST "");
7319 }
7320 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007321 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007322 return(-1);
7323 }
7324 cur = val;
7325 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007326 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007327 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007328 cur++;
7329#ifdef DEBUG_LIST
7330 nb_values++;
7331#endif
7332 while (IS_BLANK(*cur))
7333 *cur++ = 0;
7334 } else
7335 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007336 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007337#ifdef DEBUG_LIST
7338 xmlGenericError(xmlGenericErrorContext,
7339 "list value: '%s' found %d items\n", oldvalue, nb_values);
7340 nb_values = 0;
7341#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007342 ctxt->state->endvalue = cur;
7343 cur = val;
7344 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007345
Daniel Veillardfd573f12003-03-16 17:52:32 +00007346 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007347
Daniel Veillardfd573f12003-03-16 17:52:32 +00007348 while (list != NULL) {
7349 if (ctxt->state->value == ctxt->state->endvalue)
7350 ctxt->state->value = NULL;
7351 ret = xmlRelaxNGValidateValue(ctxt, list);
7352 if (ret != 0) {
7353#ifdef DEBUG_LIST
7354 xmlGenericError(xmlGenericErrorContext,
7355 "Failed to validate value: '%s' with %d rule\n",
7356 ctxt->state->value, nb_values);
7357#endif
7358 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007359 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007360#ifdef DEBUG_LIST
7361 nb_values++;
7362#endif
7363 list = list->next;
7364 }
7365
7366 if ((ret == 0) && (ctxt->state->value != NULL) &&
7367 (ctxt->state->value != ctxt->state->endvalue)) {
7368 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7369 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007370 }
7371 xmlFree(val);
7372 ctxt->state->value = oldvalue;
7373 ctxt->state->endvalue = oldend;
7374 break;
7375 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007376 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007377 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7378 if (ret != 0) {
7379 break;
7380 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007381 /* no break on purpose */
7382 case XML_RELAXNG_ZEROORMORE: {
7383 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007384
7385 oldflags = ctxt->flags;
7386 ctxt->flags |= FLAGS_IGNORABLE;
7387 cur = ctxt->state->value;
7388 temp = NULL;
7389 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7390 (temp != cur)) {
7391 temp = cur;
7392 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7393 if (ret != 0) {
7394 ctxt->state->value = temp;
7395 ret = 0;
7396 break;
7397 }
7398 cur = ctxt->state->value;
7399 }
7400 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007401 if (ret != 0) {
7402 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7403 xmlRelaxNGDumpValidError(ctxt);
7404 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007405 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007406 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007407 break;
7408 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007409 case XML_RELAXNG_EXCEPT: {
7410 xmlRelaxNGDefinePtr list;
7411
7412 list = define->content;
7413 while (list != NULL) {
7414 ret = xmlRelaxNGValidateValue(ctxt, list);
7415 if (ret == 0) {
7416 ret = -1;
7417 break;
7418 } else
7419 ret = 0;
7420 list = list->next;
7421 }
7422 break;
7423 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007424 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007425 case XML_RELAXNG_GROUP: {
7426 xmlRelaxNGDefinePtr list;
7427
7428 list = define->content;
7429 while (list != NULL) {
7430 ret = xmlRelaxNGValidateValue(ctxt, list);
7431 if (ret != 0) {
7432 ret = -1;
7433 break;
7434 } else
7435 ret = 0;
7436 list = list->next;
7437 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007438 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007439 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007440 case XML_RELAXNG_REF:
7441 case XML_RELAXNG_PARENTREF:
7442 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7443 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007444 default:
7445 TODO
7446 ret = -1;
7447 }
7448 return(ret);
7449}
7450
7451/**
7452 * xmlRelaxNGValidateValueContent:
7453 * @ctxt: a Relax-NG validation context
7454 * @defines: the list of definitions to verify
7455 *
7456 * Validate the given definitions for the current value
7457 *
7458 * Returns 0 if the validation succeeded or an error code.
7459 */
7460static int
7461xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7462 xmlRelaxNGDefinePtr defines) {
7463 int ret = 0;
7464
7465 while (defines != NULL) {
7466 ret = xmlRelaxNGValidateValue(ctxt, defines);
7467 if (ret != 0)
7468 break;
7469 defines = defines->next;
7470 }
7471 return(ret);
7472}
7473
7474/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007475 * xmlRelaxNGAttributeMatch:
7476 * @ctxt: a Relax-NG validation context
7477 * @define: the definition to check
7478 * @prop: the attribute
7479 *
7480 * Check if the attribute matches the definition nameClass
7481 *
7482 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7483 */
7484static int
7485xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7486 xmlRelaxNGDefinePtr define,
7487 xmlAttrPtr prop) {
7488 int ret;
7489
7490 if (define->name != NULL) {
7491 if (!xmlStrEqual(define->name, prop->name))
7492 return(0);
7493 }
7494 if (define->ns != NULL) {
7495 if (define->ns[0] == 0) {
7496 if (prop->ns != NULL)
7497 return(0);
7498 } else {
7499 if ((prop->ns == NULL) ||
7500 (!xmlStrEqual(define->ns, prop->ns->href)))
7501 return(0);
7502 }
7503 }
7504 if (define->nameClass == NULL)
7505 return(1);
7506 define = define->nameClass;
7507 if (define->type == XML_RELAXNG_EXCEPT) {
7508 xmlRelaxNGDefinePtr list;
7509
7510 list = define->content;
7511 while (list != NULL) {
7512 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7513 if (ret == 1)
7514 return(0);
7515 if (ret < 0)
7516 return(ret);
7517 list = list->next;
7518 }
7519 } else {
7520 TODO
7521 }
7522 return(1);
7523}
7524
7525/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007526 * xmlRelaxNGValidateAttribute:
7527 * @ctxt: a Relax-NG validation context
7528 * @define: the definition to verify
7529 *
7530 * Validate the given attribute definition for that node
7531 *
7532 * Returns 0 if the validation succeeded or an error code.
7533 */
7534static int
7535xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7536 xmlRelaxNGDefinePtr define) {
7537 int ret = 0, i;
7538 xmlChar *value, *oldvalue;
7539 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007540 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007541
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007542 if (ctxt->state->nbAttrLeft <= 0)
7543 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007544 if (define->name != NULL) {
7545 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7546 tmp = ctxt->state->attrs[i];
7547 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7548 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7549 (tmp->ns == NULL)) ||
7550 ((tmp->ns != NULL) &&
7551 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7552 prop = tmp;
7553 break;
7554 }
7555 }
7556 }
7557 if (prop != NULL) {
7558 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7559 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007560 oldseq = ctxt->state->seq;
7561 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007562 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007563 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007564 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007565 if (ctxt->state->value != NULL)
7566 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007567 if (value != NULL)
7568 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007569 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007570 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007571 if (ret == 0) {
7572 /*
7573 * flag the attribute as processed
7574 */
7575 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007576 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007577 }
7578 } else {
7579 ret = -1;
7580 }
7581#ifdef DEBUG
7582 xmlGenericError(xmlGenericErrorContext,
7583 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7584#endif
7585 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007586 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7587 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007588 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007589 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007590 prop = tmp;
7591 break;
7592 }
7593 }
7594 if (prop != NULL) {
7595 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7596 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007597 oldseq = ctxt->state->seq;
7598 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007599 ctxt->state->value = value;
7600 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007601 if (ctxt->state->value != NULL)
7602 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007603 if (value != NULL)
7604 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007605 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007606 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007607 if (ret == 0) {
7608 /*
7609 * flag the attribute as processed
7610 */
7611 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007612 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007613 }
7614 } else {
7615 ret = -1;
7616 }
7617#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007618 if (define->ns != NULL) {
7619 xmlGenericError(xmlGenericErrorContext,
7620 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7621 define->ns, ret);
7622 } else {
7623 xmlGenericError(xmlGenericErrorContext,
7624 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7625 ret);
7626 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007627#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007628 }
7629
7630 return(ret);
7631}
7632
7633/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007634 * xmlRelaxNGValidateAttributeList:
7635 * @ctxt: a Relax-NG validation context
7636 * @define: the list of definition to verify
7637 *
7638 * Validate the given node against the list of attribute definitions
7639 *
7640 * Returns 0 if the validation succeeded or an error code.
7641 */
7642static int
7643xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7644 xmlRelaxNGDefinePtr defines) {
7645 int ret = 0;
7646 while (defines != NULL) {
7647 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7648 ret = -1;
7649 defines = defines->next;
7650 }
7651 return(ret);
7652}
7653
7654/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007655 * xmlRelaxNGNodeMatchesList:
7656 * @node: the node
7657 * @list: a NULL terminated array of definitions
7658 *
7659 * Check if a node can be matched by one of the definitions
7660 *
7661 * Returns 1 if matches 0 otherwise
7662 */
7663static int
7664xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7665 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007666 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007667
7668 if ((node == NULL) || (list == NULL))
7669 return(0);
7670
7671 cur = list[i++];
7672 while (cur != NULL) {
7673 if ((node->type == XML_ELEMENT_NODE) &&
7674 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007675 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
7676 if (tmp == 1)
7677 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007678 } else if (((node->type == XML_TEXT_NODE) ||
7679 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007680 (cur->type == XML_RELAXNG_TEXT)) {
7681 return(1);
7682 }
7683 cur = list[i++];
7684 }
7685 return(0);
7686}
7687
7688/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007689 * xmlRelaxNGValidateInterleave:
7690 * @ctxt: a Relax-NG validation context
7691 * @define: the definition to verify
7692 *
7693 * Validate an interleave definition for a node.
7694 *
7695 * Returns 0 if the validation succeeded or an error code.
7696 */
7697static int
7698xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7699 xmlRelaxNGDefinePtr define) {
7700 int ret = 0, i, nbgroups, left;
7701 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007702 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007703
7704 xmlRelaxNGValidStatePtr oldstate;
7705 xmlRelaxNGPartitionPtr partitions;
7706 xmlRelaxNGInterleaveGroupPtr group = NULL;
7707 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7708 xmlNodePtr *list = NULL, *lasts = NULL;
7709
7710 if (define->data != NULL) {
7711 partitions = (xmlRelaxNGPartitionPtr) define->data;
7712 nbgroups = partitions->nbgroups;
7713 left = nbgroups;
7714 } else {
7715 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7716 return(-1);
7717 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007718 /*
7719 * Optimizations for MIXED
7720 */
7721 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00007722 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007723 ctxt->flags |= FLAGS_MIXED_CONTENT;
7724 if (nbgroups == 2) {
7725 /*
7726 * this is a pure <mixed> case
7727 */
7728 if (ctxt->state != NULL)
7729 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7730 ctxt->state->seq);
7731 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7732 ret = xmlRelaxNGValidateDefinition(ctxt,
7733 partitions->groups[1]->rule);
7734 else
7735 ret = xmlRelaxNGValidateDefinition(ctxt,
7736 partitions->groups[0]->rule);
7737 if (ret == 0) {
7738 if (ctxt->state != NULL)
7739 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7740 ctxt->state->seq);
7741 }
7742 ctxt->flags = oldflags;
7743 return(ret);
7744 }
7745 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007746
7747 /*
7748 * Build arrays to store the first and last node of the chain
7749 * pertaining to each group
7750 */
7751 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7752 if (list == NULL) {
7753 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7754 return(-1);
7755 }
7756 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7757 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7758 if (lasts == NULL) {
7759 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7760 return(-1);
7761 }
7762 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7763
7764 /*
7765 * Walk the sequence of children finding the right group and
7766 * sorting them in sequences.
7767 */
7768 cur = ctxt->state->seq;
7769 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7770 start = cur;
7771 while (cur != NULL) {
7772 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007773 if ((partitions->triage != NULL) &&
7774 (partitions->flags & IS_DETERMINIST)) {
7775 void *tmp = NULL;
7776
7777 if ((cur->type == XML_TEXT_NODE) ||
7778 (cur->type == XML_CDATA_SECTION_NODE)) {
7779 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7780 NULL);
7781 } else if (cur->type == XML_ELEMENT_NODE) {
7782 if (cur->ns != NULL) {
7783 tmp = xmlHashLookup2(partitions->triage, cur->name,
7784 cur->ns->href);
7785 if (tmp == NULL)
7786 tmp = xmlHashLookup2(partitions->triage,
7787 BAD_CAST "#any", cur->ns->href);
7788 } else
7789 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7790 if (tmp == NULL)
7791 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7792 NULL);
7793 }
7794
7795 if (tmp == NULL) {
7796 i = nbgroups;
7797 } else {
7798 i = ((long) tmp) - 1;
7799 if (partitions->flags & IS_NEEDCHECK) {
7800 group = partitions->groups[i];
7801 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7802 i = nbgroups;
7803 }
7804 }
7805 } else {
7806 for (i = 0;i < nbgroups;i++) {
7807 group = partitions->groups[i];
7808 if (group == NULL)
7809 continue;
7810 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7811 break;
7812 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007813 }
7814 /*
7815 * We break as soon as an element not matched is found
7816 */
7817 if (i >= nbgroups) {
7818 break;
7819 }
7820 if (lasts[i] != NULL) {
7821 lasts[i]->next = cur;
7822 lasts[i] = cur;
7823 } else {
7824 list[i] = cur;
7825 lasts[i] = cur;
7826 }
7827 if (cur->next != NULL)
7828 lastchg = cur->next;
7829 else
7830 lastchg = cur;
7831 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7832 }
7833 if (ret != 0) {
7834 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7835 ret = -1;
7836 goto done;
7837 }
7838 lastelem = cur;
7839 oldstate = ctxt->state;
7840 for (i = 0;i < nbgroups;i++) {
7841 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7842 group = partitions->groups[i];
7843 if (lasts[i] != NULL) {
7844 last = lasts[i]->next;
7845 lasts[i]->next = NULL;
7846 }
7847 ctxt->state->seq = list[i];
7848 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7849 if (ret != 0)
7850 break;
7851 if (ctxt->state != NULL) {
7852 cur = ctxt->state->seq;
7853 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007854 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007855 oldstate = ctxt->state;
7856 ctxt->state = NULL;
7857 if (cur != NULL) {
7858 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7859 ret = -1;
7860 ctxt->state = oldstate;
7861 goto done;
7862 }
7863 } else if (ctxt->states != NULL) {
7864 int j;
7865 int found = 0;
7866
7867 for (j = 0;j < ctxt->states->nbState;j++) {
7868 cur = ctxt->states->tabState[j]->seq;
7869 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7870 if (cur == NULL) {
7871 found = 1;
7872 break;
7873 }
7874 }
7875 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007876 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007877 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7878 }
7879 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007880 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007881 }
7882 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7883 ctxt->states = NULL;
7884 if (found == 0) {
7885 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7886 ret = -1;
7887 ctxt->state = oldstate;
7888 goto done;
7889 }
7890 } else {
7891 ret = -1;
7892 break;
7893 }
7894 if (lasts[i] != NULL) {
7895 lasts[i]->next = last;
7896 }
7897 }
7898 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007899 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007900 ctxt->state = oldstate;
7901 ctxt->state->seq = lastelem;
7902 if (ret != 0) {
7903 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7904 ret = -1;
7905 goto done;
7906 }
7907
7908done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007909 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007910 /*
7911 * builds the next links chain from the prev one
7912 */
7913 cur = lastchg;
7914 while (cur != NULL) {
7915 if ((cur == start) || (cur->prev == NULL))
7916 break;
7917 cur->prev->next = cur;
7918 cur = cur->prev;
7919 }
7920 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007921 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007922 }
7923
7924 xmlFree(list);
7925 xmlFree(lasts);
7926 return(ret);
7927}
7928
7929/**
7930 * xmlRelaxNGValidateDefinitionList:
7931 * @ctxt: a Relax-NG validation context
7932 * @define: the list of definition to verify
7933 *
7934 * Validate the given node content against the (list) of definitions
7935 *
7936 * Returns 0 if the validation succeeded or an error code.
7937 */
7938static int
7939xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7940 xmlRelaxNGDefinePtr defines) {
7941 int ret = 0, res;
7942
7943
Daniel Veillard952379b2003-03-17 15:37:12 +00007944 if (defines == NULL) {
7945 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7946 return(-1);
7947 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007948 while (defines != NULL) {
7949 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7950 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7951 if (res < 0)
7952 ret = -1;
7953 } else {
7954 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7955 return(-1);
7956 }
7957 if (ret < 0)
7958 break;
7959 defines = defines->next;
7960 }
7961
7962 return(ret);
7963}
7964
7965/**
7966 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007967 * @ctxt: a Relax-NG validation context
7968 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007969 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007970 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007971 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007972 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007973 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007974 */
7975static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007976xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7977 xmlRelaxNGDefinePtr define,
7978 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00007979 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007980
Daniel Veillardfd573f12003-03-16 17:52:32 +00007981 if (define->name != NULL) {
7982 if (!xmlStrEqual(elem->name, define->name)) {
7983 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7984 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007985 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007986 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007987 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7988 if (elem->ns == NULL) {
7989 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7990 elem->name);
7991 return(0);
7992 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7993 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7994 elem->name, define->ns);
7995 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007996 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007997 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7998 (define->name == NULL)) {
7999 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8000 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008001 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008002 } else if ((elem->ns != NULL) && (define->name != NULL)) {
8003 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8004 define->name);
8005 return(0);
8006 }
8007
8008 if (define->nameClass == NULL)
8009 return(1);
8010
8011 define = define->nameClass;
8012 if (define->type == XML_RELAXNG_EXCEPT) {
8013 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008014 if (ctxt != NULL) {
8015 oldflags = ctxt->flags;
8016 ctxt->flags |= FLAGS_IGNORABLE;
8017 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008018
8019 list = define->content;
8020 while (list != NULL) {
8021 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8022 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008023 if (ctxt != NULL)
8024 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008025 return(0);
8026 }
8027 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008028 if (ctxt != NULL)
8029 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008030 return(ret);
8031 }
8032 list = list->next;
8033 }
8034 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008035 if (ctxt != NULL) {
8036 ctxt->flags = oldflags;
8037 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008038 } else if (define->type == XML_RELAXNG_CHOICE) {
8039 xmlRelaxNGDefinePtr list;
8040
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008041 if (ctxt != NULL) {
8042 oldflags = ctxt->flags;
8043 ctxt->flags |= FLAGS_IGNORABLE;
8044 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008045
8046 list = define->nameClass;
8047 while (list != NULL) {
8048 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8049 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008050 if (ctxt != NULL)
8051 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008052 return(1);
8053 }
8054 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008055 if (ctxt != NULL)
8056 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008057 return(ret);
8058 }
8059 list = list->next;
8060 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008061 if (ctxt != NULL) {
8062 if (ret != 0) {
8063 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8064 xmlRelaxNGDumpValidError(ctxt);
8065 } else {
8066 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8067 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008068 }
8069 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008070 if (ctxt != NULL) {
8071 ctxt->flags = oldflags;
8072 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008073 } else {
8074 TODO
8075 ret = -1;
8076 }
8077 return(ret);
8078}
8079
8080/**
8081 * xmlRelaxNGValidateElementEnd:
8082 * @ctxt: a Relax-NG validation context
8083 *
8084 * Validate the end of the element, implements check that
8085 * there is nothing left not consumed in the element content
8086 * or in the attribute list.
8087 *
8088 * Returns 0 if the validation succeeded or an error code.
8089 */
8090static int
8091xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8092 int ret = 0, i;
8093 xmlRelaxNGValidStatePtr state;
8094
8095 state = ctxt->state;
8096 if (state->seq != NULL) {
8097 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8098 if (state->seq != NULL) {
8099 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8100 state->node->name, state->seq->name);
8101 ret = -1;
8102 }
8103 }
8104 for (i = 0;i < state->nbAttrs;i++) {
8105 if (state->attrs[i] != NULL) {
8106 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8107 state->attrs[i]->name, state->node->name);
8108 ret = -1;
8109 }
8110 }
8111 return(ret);
8112}
8113
8114/**
8115 * xmlRelaxNGValidateState:
8116 * @ctxt: a Relax-NG validation context
8117 * @define: the definition to verify
8118 *
8119 * Validate the current state against the definition
8120 *
8121 * Returns 0 if the validation succeeded or an error code.
8122 */
8123static int
8124xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8125 xmlRelaxNGDefinePtr define) {
8126 xmlNodePtr node;
8127 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008128 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008129
8130 if (define == NULL) {
8131 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8132 return(-1);
8133 }
8134
8135 if (ctxt->state != NULL) {
8136 node = ctxt->state->seq;
8137 } else {
8138 node = NULL;
8139 }
8140#ifdef DEBUG
8141 for (i = 0;i < ctxt->depth;i++)
8142 xmlGenericError(xmlGenericErrorContext, " ");
8143 xmlGenericError(xmlGenericErrorContext,
8144 "Start validating %s ", xmlRelaxNGDefName(define));
8145 if (define->name != NULL)
8146 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8147 if ((node != NULL) && (node->name != NULL))
8148 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8149 else
8150 xmlGenericError(xmlGenericErrorContext, "\n");
8151#endif
8152 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008153 switch (define->type) {
8154 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008155 node = xmlRelaxNGSkipIgnored(ctxt, node);
8156 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008157 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008158 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008159 ret = -1;
8160 break;
8161 case XML_RELAXNG_TEXT:
8162 while ((node != NULL) &&
8163 ((node->type == XML_TEXT_NODE) ||
8164 (node->type == XML_COMMENT_NODE) ||
8165 (node->type == XML_PI_NODE) ||
8166 (node->type == XML_CDATA_SECTION_NODE)))
8167 node = node->next;
8168 ctxt->state->seq = node;
8169 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008170 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008171 errNr = ctxt->errNr;
8172 node = xmlRelaxNGSkipIgnored(ctxt, node);
8173 if (node == NULL) {
8174 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8175 ret = -1;
8176 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8177 xmlRelaxNGDumpValidError(ctxt);
8178 break;
8179 }
8180 if (node->type != XML_ELEMENT_NODE) {
8181 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8182 ret = -1;
8183 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8184 xmlRelaxNGDumpValidError(ctxt);
8185 break;
8186 }
8187 /*
8188 * This node was already validated successfully against
8189 * this definition.
8190 */
8191 if (node->_private == define) {
8192 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard580ced82003-03-21 21:22:48 +00008193 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008194 if (ctxt->errNr != 0) {
8195 while ((ctxt->err != NULL) &&
8196 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8197 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008198 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8199 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008200 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8201 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8202 xmlRelaxNGValidErrorPop(ctxt);
8203 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008204 break;
8205 }
8206
8207 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8208 if (ret <= 0) {
8209 ret = -1;
8210 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8211 xmlRelaxNGDumpValidError(ctxt);
8212 break;
8213 }
8214 ret = 0;
8215 if (ctxt->errNr != 0) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008216 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008217 while ((ctxt->err != NULL) &&
8218 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8219 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008220 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8221 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00008222 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8223 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8224 xmlRelaxNGValidErrorPop(ctxt);
8225 }
8226 errNr = ctxt->errNr;
8227
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008228 oldflags = ctxt->flags;
8229 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8230 ctxt->flags -= FLAGS_MIXED_CONTENT;
8231 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008232 state = xmlRelaxNGNewValidState(ctxt, node);
8233 if (state == NULL) {
8234 ret = -1;
8235 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8236 xmlRelaxNGDumpValidError(ctxt);
8237 break;
8238 }
8239
8240 oldstate = ctxt->state;
8241 ctxt->state = state;
8242 if (define->attrs != NULL) {
8243 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8244 if (tmp != 0) {
8245 ret = -1;
8246 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8247 }
8248 }
8249 if (define->content != NULL) {
8250 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8251 if (tmp != 0) {
8252 ret = -1;
8253 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8254 }
8255 }
8256 if (ctxt->states != NULL) {
8257 tmp = -1;
8258
Daniel Veillardfd573f12003-03-16 17:52:32 +00008259 ctxt->flags |= FLAGS_IGNORABLE;
8260
8261 for (i = 0;i < ctxt->states->nbState;i++) {
8262 state = ctxt->states->tabState[i];
8263 ctxt->state = state;
8264
8265 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8266 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008267 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008268 }
8269 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8270 ctxt->flags = oldflags;
8271 ctxt->states = NULL;
8272 if ((ret == 0) && (tmp == -1))
8273 ret = -1;
8274 } else {
8275 state = ctxt->state;
8276 if (ret == 0)
8277 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008278 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008279 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008280 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008281 ctxt->state = oldstate;
8282 if (oldstate != NULL)
8283 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8284 if (ret == 0) {
8285 node->_private = define;
8286 }
8287 if (ret != 0) {
8288 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8289 xmlRelaxNGDumpValidError(ctxt);
8290 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008291 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008292 }
8293
8294#ifdef DEBUG
8295 xmlGenericError(xmlGenericErrorContext,
8296 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8297 node->name, ret);
8298 if (oldstate == NULL)
8299 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8300 else if (oldstate->seq == NULL)
8301 xmlGenericError(xmlGenericErrorContext, ": done\n");
8302 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8303 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8304 oldstate->seq->name);
8305 else
8306 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8307 oldstate->seq->name, oldstate->seq->type);
8308#endif
8309 break;
8310 case XML_RELAXNG_OPTIONAL: {
8311 oldflags = ctxt->flags;
8312 ctxt->flags |= FLAGS_IGNORABLE;
8313 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8314 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8315 if (ret != 0) {
8316 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008317 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008318 ctxt->state = oldstate;
8319 ctxt->flags = oldflags;
8320 ret = 0;
8321 break;
8322 }
8323 if (ctxt->states != NULL) {
8324 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8325 } else {
8326 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8327 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008328 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008329 ctxt->flags = oldflags;
8330 ret = -1;
8331 break;
8332 }
8333 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8334 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8335 ctxt->state = NULL;
8336 }
8337 ctxt->flags = oldflags;
8338 ret = 0;
8339 break;
8340 }
8341 case XML_RELAXNG_ONEORMORE:
8342 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8343 if (ret != 0) {
8344 break;
8345 }
8346 /* no break on purpose */
8347 case XML_RELAXNG_ZEROORMORE: {
8348 int progress;
8349 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8350 int base, j;
8351
8352 res = xmlRelaxNGNewStates(ctxt, 1);
8353 if (res == NULL) {
8354 ret = -1;
8355 break;
8356 }
8357 /*
8358 * All the input states are also exit states
8359 */
8360 if (ctxt->state != NULL) {
8361 xmlRelaxNGAddStates(ctxt, res,
8362 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8363 } else {
8364 for (j = 0;j < ctxt->states->nbState;j++) {
8365 xmlRelaxNGAddStates(ctxt, res,
8366 xmlRelaxNGCopyValidState(ctxt,
8367 ctxt->states->tabState[j]));
8368 }
8369 }
8370 oldflags = ctxt->flags;
8371 ctxt->flags |= FLAGS_IGNORABLE;
8372 do {
8373 progress = 0;
8374 base = res->nbState;
8375
8376 if (ctxt->states != NULL) {
8377 states = ctxt->states;
8378 for (i = 0;i < states->nbState;i++) {
8379 ctxt->state = states->tabState[i];
8380 ctxt->states = NULL;
8381 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8382 define->content);
8383 if (ret == 0) {
8384 if (ctxt->state != NULL) {
8385 tmp = xmlRelaxNGAddStates(ctxt, res,
8386 ctxt->state);
8387 ctxt->state = NULL;
8388 if (tmp == 1)
8389 progress = 1;
8390 } else if (ctxt->states != NULL) {
8391 for (j = 0;j < ctxt->states->nbState;j++) {
8392 tmp = xmlRelaxNGAddStates(ctxt, res,
8393 ctxt->states->tabState[j]);
8394 if (tmp == 1)
8395 progress = 1;
8396 }
8397 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8398 ctxt->states = NULL;
8399 }
8400 } else {
8401 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008402 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008403 ctxt->state = NULL;
8404 }
8405 }
8406 }
8407 } else {
8408 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8409 define->content);
8410 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008411 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008412 ctxt->state = NULL;
8413 } else {
8414 base = res->nbState;
8415 if (ctxt->state != NULL) {
8416 tmp = xmlRelaxNGAddStates(ctxt, res,
8417 ctxt->state);
8418 ctxt->state = NULL;
8419 if (tmp == 1)
8420 progress = 1;
8421 } else if (ctxt->states != NULL) {
8422 for (j = 0;j < ctxt->states->nbState;j++) {
8423 tmp = xmlRelaxNGAddStates(ctxt, res,
8424 ctxt->states->tabState[j]);
8425 if (tmp == 1)
8426 progress = 1;
8427 }
8428 if (states == NULL) {
8429 states = ctxt->states;
8430 } else {
8431 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8432 }
8433 ctxt->states = NULL;
8434 }
8435 }
8436 }
8437 if (progress) {
8438 /*
8439 * Collect all the new nodes added at that step
8440 * and make them the new node set
8441 */
8442 if (res->nbState - base == 1) {
8443 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8444 res->tabState[base]);
8445 } else {
8446 if (states == NULL) {
8447 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8448 }
8449 states->nbState = 0;
8450 for (i = base;i < res->nbState;i++)
8451 xmlRelaxNGAddStates(ctxt, states,
8452 xmlRelaxNGCopyValidState(ctxt,
8453 res->tabState[i]));
8454 ctxt->states = states;
8455 }
8456 }
8457 } while (progress == 1);
8458 if (states != NULL) {
8459 xmlRelaxNGFreeStates(ctxt, states);
8460 }
8461 ctxt->states = res;
8462 ctxt->flags = oldflags;
8463 ret = 0;
8464 break;
8465 }
8466 case XML_RELAXNG_CHOICE: {
Daniel Veillard580ced82003-03-21 21:22:48 +00008467 xmlRelaxNGDefinePtr list = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008468 xmlRelaxNGStatesPtr states = NULL;
8469
Daniel Veillarde063f482003-03-21 16:53:17 +00008470 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008471
Daniel Veillarde063f482003-03-21 16:53:17 +00008472 if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
8473 xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
8474
8475 /*
8476 * Something we can optimize cleanly there is only one
8477 * possble branch out !
8478 */
8479 if (node == NULL) {
8480 ret = -1;
8481 break;
8482 }
8483 if ((node->type == XML_TEXT_NODE) ||
8484 (node->type == XML_CDATA_SECTION_NODE)) {
8485 list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
8486 } else if (node->type == XML_ELEMENT_NODE) {
8487 if (node->ns != NULL) {
8488 list = xmlHashLookup2(triage, node->name,
8489 node->ns->href);
8490 if (list == NULL)
8491 list = xmlHashLookup2(triage, BAD_CAST "#any",
8492 node->ns->href);
8493 } else
8494 list = xmlHashLookup2(triage, node->name, NULL);
8495 if (list == NULL)
8496 list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
8497 }
8498 if (list == NULL) {
8499 ret = -1;
8500 break;
8501 }
8502 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8503 break;
8504 }
8505
8506 list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008507 oldflags = ctxt->flags;
8508 errNr = ctxt->errNr;
8509 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008510
8511 while (list != NULL) {
8512 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8513 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8514 if (ret == 0) {
8515 if (states == NULL) {
8516 states = xmlRelaxNGNewStates(ctxt, 1);
8517 }
8518 if (ctxt->state != NULL) {
8519 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8520 } else if (ctxt->states != NULL) {
8521 for (i = 0;i < ctxt->states->nbState;i++) {
8522 xmlRelaxNGAddStates(ctxt, states,
8523 ctxt->states->tabState[i]);
8524 }
8525 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8526 ctxt->states = NULL;
8527 }
8528 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008529 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008530 }
8531 ctxt->state = oldstate;
8532 list = list->next;
8533 }
8534 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008535 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008536 ctxt->states = states;
8537 ctxt->state = NULL;
8538 ret = 0;
8539 } else {
8540 ctxt->states = NULL;
8541 }
8542 ctxt->flags = oldflags;
8543 if (ret != 0) {
8544 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8545 xmlRelaxNGDumpValidError(ctxt);
8546 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008547 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008548 }
8549 break;
8550 }
8551 case XML_RELAXNG_DEF:
8552 case XML_RELAXNG_GROUP:
8553 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008554 break;
8555 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008556 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008557 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008558 case XML_RELAXNG_ATTRIBUTE:
8559 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8560 break;
8561 case XML_RELAXNG_NOOP:
8562 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008563 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008564 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8565 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008566 case XML_RELAXNG_PARENTREF:
8567 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8568 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008569 case XML_RELAXNG_DATATYPE: {
8570 xmlNodePtr child;
8571 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008572
Daniel Veillardfd573f12003-03-16 17:52:32 +00008573 child = node;
8574 while (child != NULL) {
8575 if (child->type == XML_ELEMENT_NODE) {
8576 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8577 node->parent->name);
8578 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008579 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008580 } else if ((child->type == XML_TEXT_NODE) ||
8581 (child->type == XML_CDATA_SECTION_NODE)) {
8582 content = xmlStrcat(content, child->content);
8583 }
8584 /* TODO: handle entities ... */
8585 child = child->next;
8586 }
8587 if (ret == -1) {
8588 if (content != NULL)
8589 xmlFree(content);
8590 break;
8591 }
8592 if (content == NULL) {
8593 content = xmlStrdup(BAD_CAST "");
8594 if (content == NULL) {
8595 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8596 ret = -1;
8597 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008598 }
8599 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008600 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8601 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008602 if (ret == -1) {
8603 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8604 } else if (ret == 0) {
8605 ctxt->state->seq = NULL;
8606 }
8607 if (content != NULL)
8608 xmlFree(content);
8609 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008610 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008611 case XML_RELAXNG_VALUE: {
8612 xmlChar *content = NULL;
8613 xmlChar *oldvalue;
8614 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008615
Daniel Veillardfd573f12003-03-16 17:52:32 +00008616 child = node;
8617 while (child != NULL) {
8618 if (child->type == XML_ELEMENT_NODE) {
8619 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8620 node->parent->name);
8621 ret = -1;
8622 break;
8623 } else if ((child->type == XML_TEXT_NODE) ||
8624 (child->type == XML_CDATA_SECTION_NODE)) {
8625 content = xmlStrcat(content, child->content);
8626 }
8627 /* TODO: handle entities ... */
8628 child = child->next;
8629 }
8630 if (ret == -1) {
8631 if (content != NULL)
8632 xmlFree(content);
8633 break;
8634 }
8635 if (content == NULL) {
8636 content = xmlStrdup(BAD_CAST "");
8637 if (content == NULL) {
8638 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8639 ret = -1;
8640 break;
8641 }
8642 }
8643 oldvalue = ctxt->state->value;
8644 ctxt->state->value = content;
8645 ret = xmlRelaxNGValidateValue(ctxt, define);
8646 ctxt->state->value = oldvalue;
8647 if (ret == -1) {
8648 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8649 } else if (ret == 0) {
8650 ctxt->state->seq = NULL;
8651 }
8652 if (content != NULL)
8653 xmlFree(content);
8654 break;
8655 }
8656 case XML_RELAXNG_LIST: {
8657 xmlChar *content;
8658 xmlNodePtr child;
8659 xmlChar *oldvalue, *oldendvalue;
8660 int len;
8661
8662 /*
8663 * Make sure it's only text nodes
8664 */
8665
8666 content = NULL;
8667 child = node;
8668 while (child != NULL) {
8669 if (child->type == XML_ELEMENT_NODE) {
8670 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8671 node->parent->name);
8672 ret = -1;
8673 break;
8674 } else if ((child->type == XML_TEXT_NODE) ||
8675 (child->type == XML_CDATA_SECTION_NODE)) {
8676 content = xmlStrcat(content, child->content);
8677 }
8678 /* TODO: handle entities ... */
8679 child = child->next;
8680 }
8681 if (ret == -1) {
8682 if (content != NULL)
8683 xmlFree(content);
8684 break;
8685 }
8686 if (content == NULL) {
8687 content = xmlStrdup(BAD_CAST "");
8688 if (content == NULL) {
8689 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8690 ret = -1;
8691 break;
8692 }
8693 }
8694 len = xmlStrlen(content);
8695 oldvalue = ctxt->state->value;
8696 oldendvalue = ctxt->state->endvalue;
8697 ctxt->state->value = content;
8698 ctxt->state->endvalue = content + len;
8699 ret = xmlRelaxNGValidateValue(ctxt, define);
8700 ctxt->state->value = oldvalue;
8701 ctxt->state->endvalue = oldendvalue;
8702 if (ret == -1) {
8703 VALID_ERR(XML_RELAXNG_ERR_LIST);
8704 } else if ((ret == 0) && (node != NULL)) {
8705 ctxt->state->seq = node->next;
8706 }
8707 if (content != NULL)
8708 xmlFree(content);
8709 break;
8710 }
8711 case XML_RELAXNG_START:
8712 case XML_RELAXNG_EXCEPT:
8713 case XML_RELAXNG_PARAM:
8714 TODO
8715 ret = -1;
8716 break;
8717 }
8718 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008719#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008720 for (i = 0;i < ctxt->depth;i++)
8721 xmlGenericError(xmlGenericErrorContext, " ");
8722 xmlGenericError(xmlGenericErrorContext,
8723 "Validating %s ", xmlRelaxNGDefName(define));
8724 if (define->name != NULL)
8725 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8726 if (ret == 0)
8727 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8728 else
8729 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008730#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008731 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008732}
8733
8734/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008735 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008736 * @ctxt: a Relax-NG validation context
8737 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008738 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008739 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008740 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008741 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008742 */
8743static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008744xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8745 xmlRelaxNGDefinePtr define) {
8746 xmlRelaxNGStatesPtr states, res;
8747 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008748
Daniel Veillardfd573f12003-03-16 17:52:32 +00008749 /*
8750 * We should NOT have both ctxt->state and ctxt->states
8751 */
8752 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8753 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008754 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008755 ctxt->state = NULL;
8756 }
8757
8758 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8759 if (ctxt->states != NULL) {
8760 ctxt->state = ctxt->states->tabState[0];
8761 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8762 ctxt->states = NULL;
8763 }
8764 ret = xmlRelaxNGValidateState(ctxt, define);
8765 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8766 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008767 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008768 ctxt->state = NULL;
8769 }
8770 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8771 ctxt->state = ctxt->states->tabState[0];
8772 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8773 ctxt->states = NULL;
8774 }
8775 return(ret);
8776 }
8777
8778 states = ctxt->states;
8779 ctxt->states = NULL;
8780 res = NULL;
8781 j = 0;
8782 oldflags = ctxt->flags;
8783 ctxt->flags |= FLAGS_IGNORABLE;
8784 for (i = 0;i < states->nbState;i++) {
8785 ctxt->state = states->tabState[i];
8786 ctxt->states = NULL;
8787 ret = xmlRelaxNGValidateState(ctxt, define);
8788 /*
8789 * We should NOT have both ctxt->state and ctxt->states
8790 */
8791 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8792 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008793 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008794 ctxt->state = NULL;
8795 }
8796 if (ret == 0) {
8797 if (ctxt->states == NULL) {
8798 if (res != NULL) {
8799 /* add the state to the container */
8800 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8801 ctxt->state = NULL;
8802 } else {
8803 /* add the state directly in states */
8804 states->tabState[j++] = ctxt->state;
8805 ctxt->state = NULL;
8806 }
8807 } else {
8808 if (res == NULL) {
8809 /* make it the new container and copy other results */
8810 res = ctxt->states;
8811 ctxt->states = NULL;
8812 for (k = 0;k < j;k++)
8813 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8814 } else {
8815 /* add all the new results to res and reff the container */
8816 for (k = 0;k < ctxt->states->nbState;k++)
8817 xmlRelaxNGAddStates(ctxt, res,
8818 ctxt->states->tabState[k]);
8819 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8820 ctxt->states = NULL;
8821 }
8822 }
8823 } else {
8824 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008825 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008826 ctxt->state = NULL;
8827 } else if (ctxt->states != NULL) {
8828 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008829 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008830 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8831 ctxt->states = NULL;
8832 }
8833 }
8834 }
8835 ctxt->flags = oldflags;
8836 if (res != NULL) {
8837 xmlRelaxNGFreeStates(ctxt, states);
8838 ctxt->states = res;
8839 ret = 0;
8840 } else if (j > 1) {
8841 states->nbState = j;
8842 ctxt->states = states;
8843 ret =0;
8844 } else if (j == 1) {
8845 ctxt->state = states->tabState[0];
8846 xmlRelaxNGFreeStates(ctxt, states);
8847 ret = 0;
8848 } else {
8849 ret = -1;
8850 xmlRelaxNGFreeStates(ctxt, states);
8851 if (ctxt->states != NULL) {
8852 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8853 ctxt->states = NULL;
8854 }
8855 }
8856 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8857 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008858 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008859 ctxt->state = NULL;
8860 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008861 return(ret);
8862}
8863
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008864/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008865 * xmlRelaxNGValidateDocument:
8866 * @ctxt: a Relax-NG validation context
8867 * @doc: the document
8868 *
8869 * Validate the given document
8870 *
8871 * Returns 0 if the validation succeeded or an error code.
8872 */
8873static int
8874xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8875 int ret;
8876 xmlRelaxNGPtr schema;
8877 xmlRelaxNGGrammarPtr grammar;
8878 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008879 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008880
8881 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8882 return(-1);
8883
8884 schema = ctxt->schema;
8885 grammar = schema->topgrammar;
8886 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008887 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008888 return(-1);
8889 }
8890 state = xmlRelaxNGNewValidState(ctxt, NULL);
8891 ctxt->state = state;
8892 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008893 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8894 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008895 node = state->seq;
8896 node = xmlRelaxNGSkipIgnored(ctxt, node);
8897 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008898 if (ret != -1) {
8899 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8900 ret = -1;
8901 }
8902 }
8903 } else if (ctxt->states != NULL) {
8904 int i;
8905 int tmp = -1;
8906
8907 for (i = 0;i < ctxt->states->nbState;i++) {
8908 state = ctxt->states->tabState[i];
8909 node = state->seq;
8910 node = xmlRelaxNGSkipIgnored(ctxt, node);
8911 if (node == NULL)
8912 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008913 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008914 }
8915 if (tmp == -1) {
8916 if (ret != -1) {
8917 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8918 ret = -1;
8919 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008920 }
8921 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008922 if (ctxt->state != NULL) {
8923 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8924 ctxt->state = NULL;
8925 }
Daniel Veillard580ced82003-03-21 21:22:48 +00008926 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00008927 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00008928#ifdef DEBUG
8929 else if (ctxt->errNr != 0) {
8930 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
8931 ctxt->errNr);
8932 xmlRelaxNGDumpValidError(ctxt);
8933 }
8934#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008935 if (ctxt->idref == 1) {
8936 xmlValidCtxt vctxt;
8937
8938 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8939 vctxt.valid = 1;
8940 vctxt.error = ctxt->error;
8941 vctxt.warning = ctxt->warning;
8942 vctxt.userData = ctxt->userData;
8943
8944 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8945 ret = -1;
8946 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008947
8948 return(ret);
8949}
8950
Daniel Veillardfd573f12003-03-16 17:52:32 +00008951/************************************************************************
8952 * *
8953 * Validation interfaces *
8954 * *
8955 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008956/**
8957 * xmlRelaxNGNewValidCtxt:
8958 * @schema: a precompiled XML RelaxNGs
8959 *
8960 * Create an XML RelaxNGs validation context based on the given schema
8961 *
8962 * Returns the validation context or NULL in case of error
8963 */
8964xmlRelaxNGValidCtxtPtr
8965xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8966 xmlRelaxNGValidCtxtPtr ret;
8967
8968 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8969 if (ret == NULL) {
8970 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008971 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008972 return (NULL);
8973 }
8974 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8975 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008976 ret->error = xmlGenericError;
8977 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008978 ret->errNr = 0;
8979 ret->errMax = 0;
8980 ret->err = NULL;
8981 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008982 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00008983 ret->states = NULL;
8984 ret->freeState = NULL;
8985 ret->freeStates = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008986 return (ret);
8987}
8988
8989/**
8990 * xmlRelaxNGFreeValidCtxt:
8991 * @ctxt: the schema validation context
8992 *
8993 * Free the resources associated to the schema validation context
8994 */
8995void
8996xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008997 int k;
8998
Daniel Veillard6eadf632003-01-23 18:29:16 +00008999 if (ctxt == NULL)
9000 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009001 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009002 xmlRelaxNGFreeStates(NULL, ctxt->states);
9003 if (ctxt->freeState != NULL) {
9004 for (k = 0;k < ctxt->freeState->nbState;k++) {
9005 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
9006 }
9007 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
9008 }
Daniel Veillard798024a2003-03-19 10:36:09 +00009009 if (ctxt->freeStates != NULL) {
9010 for (k = 0;k < ctxt->freeStatesNr;k++) {
9011 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
9012 }
9013 xmlFree(ctxt->freeStates);
9014 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00009015 if (ctxt->errTab != NULL)
9016 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009017 xmlFree(ctxt);
9018}
9019
9020/**
9021 * xmlRelaxNGSetValidErrors:
9022 * @ctxt: a Relax-NG validation context
9023 * @err: the error function
9024 * @warn: the warning function
9025 * @ctx: the functions context
9026 *
9027 * Set the error and warning callback informations
9028 */
9029void
9030xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
9031 xmlRelaxNGValidityErrorFunc err,
9032 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
9033 if (ctxt == NULL)
9034 return;
9035 ctxt->error = err;
9036 ctxt->warning = warn;
9037 ctxt->userData = ctx;
9038}
9039
9040/**
9041 * xmlRelaxNGValidateDoc:
9042 * @ctxt: a Relax-NG validation context
9043 * @doc: a parsed document tree
9044 *
9045 * Validate a document tree in memory.
9046 *
9047 * Returns 0 if the document is valid, a positive error code
9048 * number otherwise and -1 in case of internal or API error.
9049 */
9050int
9051xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9052 int ret;
9053
9054 if ((ctxt == NULL) || (doc == NULL))
9055 return(-1);
9056
9057 ctxt->doc = doc;
9058
9059 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00009060 /*
9061 * TODO: build error codes
9062 */
9063 if (ret == -1)
9064 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009065 return(ret);
9066}
9067
9068#endif /* LIBXML_SCHEMAS_ENABLED */
9069