blob: b8c0b5c2776ec4197e39f97a82579e00f376a47f [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:
1853 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1854 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;
1915 case XML_RELAXNG_ERR_DATAELEM:
1916 snprintf(msg, 1000, "Datatype element %s has child elements",
1917 arg1);
1918 break;
1919 case XML_RELAXNG_ERR_VALELEM:
1920 snprintf(msg, 1000, "Value element %s has child elements",
1921 arg1);
1922 break;
1923 case XML_RELAXNG_ERR_LISTELEM:
1924 snprintf(msg, 1000, "List element %s has child elements",
1925 arg1);
1926 break;
1927 case XML_RELAXNG_ERR_DATATYPE:
1928 snprintf(msg, 1000, "Error validating datatype %s",
1929 arg1);
1930 break;
1931 case XML_RELAXNG_ERR_VALUE:
1932 snprintf(msg, 1000, "Error validating value %s",
1933 arg1);
1934 break;
1935 case XML_RELAXNG_ERR_LIST:
1936 return(xmlCharStrdup("Error validating list"));
1937 case XML_RELAXNG_ERR_NOGRAMMAR:
1938 return(xmlCharStrdup("No top grammar defined"));
1939 case XML_RELAXNG_ERR_EXTRADATA:
1940 return(xmlCharStrdup("Extra data in the document"));
1941 default:
1942 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001943 }
1944 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001945 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001946 }
1947 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001948 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001949}
1950
1951/**
1952 * xmlRelaxNGValidErrorContext:
1953 * @ctxt: the validation context
1954 * @node: the node
1955 * @child: the node child generating the problem.
1956 *
1957 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001958 */
1959static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001960xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1961 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001962{
1963 int line = 0;
1964 const xmlChar *file = NULL;
1965 const xmlChar *name = NULL;
1966 const char *type = "error";
1967
1968 if ((ctxt == NULL) || (ctxt->error == NULL))
1969 return;
1970
1971 if (child != NULL)
1972 node = child;
1973
1974 if (node != NULL) {
1975 if ((node->type == XML_DOCUMENT_NODE) ||
1976 (node->type == XML_HTML_DOCUMENT_NODE)) {
1977 xmlDocPtr doc = (xmlDocPtr) node;
1978
1979 file = doc->URL;
1980 } else {
1981 /*
1982 * Try to find contextual informations to report
1983 */
1984 if (node->type == XML_ELEMENT_NODE) {
1985 line = (int) node->content;
1986 } else if ((node->prev != NULL) &&
1987 (node->prev->type == XML_ELEMENT_NODE)) {
1988 line = (int) node->prev->content;
1989 } else if ((node->parent != NULL) &&
1990 (node->parent->type == XML_ELEMENT_NODE)) {
1991 line = (int) node->parent->content;
1992 }
1993 if ((node->doc != NULL) && (node->doc->URL != NULL))
1994 file = node->doc->URL;
1995 if (node->name != NULL)
1996 name = node->name;
1997 }
1998 }
1999
Daniel Veillard42f12e92003-03-07 18:32:59 +00002000 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002001
2002 if ((file != NULL) && (line != 0) && (name != NULL))
2003 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2004 type, file, line, name);
2005 else if ((file != NULL) && (name != NULL))
2006 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2007 type, file, name);
2008 else if ((file != NULL) && (line != 0))
2009 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2010 else if (file != NULL)
2011 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2012 else if (name != NULL)
2013 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2014 else
2015 ctxt->error(ctxt->userData, "%s\n", type);
2016}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002017
2018/**
2019 * xmlRelaxNGShowValidError:
2020 * @ctxt: the validation context
2021 * @err: the error number
2022 * @node: the node
2023 * @child: the node child generating the problem.
2024 * @arg1: the first argument
2025 * @arg2: the second argument
2026 *
2027 * Show a validation error.
2028 */
2029static void
2030xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2031 xmlNodePtr node, xmlNodePtr child,
2032 const xmlChar *arg1, const xmlChar *arg2)
2033{
2034 xmlChar *msg;
2035
2036 if (ctxt->error == NULL)
2037 return;
2038
2039 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2040 if (msg == NULL)
2041 return;
2042
2043 xmlRelaxNGValidErrorContext(ctxt, node, child);
2044 ctxt->error(ctxt->userData, "%s\n", msg);
2045 xmlFree(msg);
2046}
2047
2048/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002049 * xmlRelaxNGPopErrors:
2050 * @ctxt: the validation context
2051 * @level: the error level in the stack
2052 *
2053 * pop and discard all errors until the given level is reached
2054 */
2055static void
2056xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2057 int i;
2058 xmlRelaxNGValidErrorPtr err;
2059
2060 for (i = level;i < ctxt->errNr;i++) {
2061 err = &ctxt->errTab[i];
2062 if (err->flags & ERROR_IS_DUP) {
2063 if (err->arg1 != NULL)
2064 xmlFree((xmlChar *)err->arg1);
2065 err->arg1 = NULL;
2066 if (err->arg2 != NULL)
2067 xmlFree((xmlChar *)err->arg2);
2068 err->arg2 = NULL;
2069 err->flags = 0;
2070 }
2071 }
2072 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002073 if (ctxt->errNr <= 0)
2074 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002075}
2076/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002077 * xmlRelaxNGDumpValidError:
2078 * @ctxt: the validation context
2079 *
2080 * Show all validation error over a given index.
2081 */
2082static void
2083xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002084 int i, j;
2085 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002086
2087 for (i = 0;i < ctxt->errNr;i++) {
2088 err = &ctxt->errTab[i];
Daniel Veillard580ced82003-03-21 21:22:48 +00002089 for (j = 0;j < i;j++) {
2090 dup = &ctxt->errTab[j];
2091 if ((err->err == dup->err) && (err->node == dup->node) &&
2092 (xmlStrEqual(err->arg1, dup->arg1)) &&
2093 (xmlStrEqual(err->arg2, dup->arg2))) {
2094 goto skip;
2095 }
2096 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002097 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2098 err->arg1, err->arg2);
Daniel Veillard580ced82003-03-21 21:22:48 +00002099skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002100 if (err->flags & ERROR_IS_DUP) {
2101 if (err->arg1 != NULL)
2102 xmlFree((xmlChar *)err->arg1);
2103 err->arg1 = NULL;
2104 if (err->arg2 != NULL)
2105 xmlFree((xmlChar *)err->arg2);
2106 err->arg2 = NULL;
2107 err->flags = 0;
2108 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002109 }
2110 ctxt->errNr = 0;
2111}
2112/**
2113 * xmlRelaxNGAddValidError:
2114 * @ctxt: the validation context
2115 * @err: the error number
2116 * @arg1: the first argument
2117 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002118 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002119 *
2120 * Register a validation error, either generating it if it's sure
2121 * or stacking it for later handling if unsure.
2122 */
2123static void
2124xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002125 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002126{
2127 if ((ctxt == NULL) || (ctxt->error == NULL))
2128 return;
2129
2130 /*
2131 * generate the error directly
2132 */
2133 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2134 xmlNodePtr node, seq;
2135 /*
2136 * Flush first any stacked error which might be the
2137 * real cause of the problem.
2138 */
2139 if (ctxt->errNr != 0)
2140 xmlRelaxNGDumpValidError(ctxt);
2141 if (ctxt->state != NULL) {
2142 node = ctxt->state->node;
2143 seq = ctxt->state->seq;
2144 } else {
2145 node = seq = NULL;
2146 }
2147 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2148 }
2149 /*
2150 * Stack the error for later processing if needed
2151 */
2152 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002153 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002154 }
2155}
2156
Daniel Veillard6eadf632003-01-23 18:29:16 +00002157
2158/************************************************************************
2159 * *
2160 * Type library hooks *
2161 * *
2162 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002163static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2164 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002165
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002166/**
2167 * xmlRelaxNGSchemaTypeHave:
2168 * @data: data needed for the library
2169 * @type: the type name
2170 *
2171 * Check if the given type is provided by
2172 * the W3C XMLSchema Datatype library.
2173 *
2174 * Returns 1 if yes, 0 if no and -1 in case of error.
2175 */
2176static int
2177xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002178 const xmlChar *type) {
2179 xmlSchemaTypePtr typ;
2180
2181 if (type == NULL)
2182 return(-1);
2183 typ = xmlSchemaGetPredefinedType(type,
2184 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2185 if (typ == NULL)
2186 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002187 return(1);
2188}
2189
2190/**
2191 * xmlRelaxNGSchemaTypeCheck:
2192 * @data: data needed for the library
2193 * @type: the type name
2194 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002195 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002196 *
2197 * Check if the given type and value are validated by
2198 * the W3C XMLSchema Datatype library.
2199 *
2200 * Returns 1 if yes, 0 if no and -1 in case of error.
2201 */
2202static int
2203xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002204 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002205 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002206 void **result,
2207 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002208 xmlSchemaTypePtr typ;
2209 int ret;
2210
2211 /*
2212 * TODO: the type should be cached ab provided back, interface subject
2213 * to changes.
2214 * TODO: handle facets, may require an additional interface and keep
2215 * the value returned from the validation.
2216 */
2217 if ((type == NULL) || (value == NULL))
2218 return(-1);
2219 typ = xmlSchemaGetPredefinedType(type,
2220 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2221 if (typ == NULL)
2222 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002223 ret = xmlSchemaValPredefTypeNode(typ, value,
2224 (xmlSchemaValPtr *) result, node);
2225 if (ret == 2) /* special ID error code */
2226 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002227 if (ret == 0)
2228 return(1);
2229 if (ret > 0)
2230 return(0);
2231 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002232}
2233
2234/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002235 * xmlRelaxNGSchemaFacetCheck:
2236 * @data: data needed for the library
2237 * @type: the type name
2238 * @facet: the facet name
2239 * @val: the facet value
2240 * @strval: the string value
2241 * @value: the value to check
2242 *
2243 * Function provided by a type library to check a value facet
2244 *
2245 * Returns 1 if yes, 0 if no and -1 in case of error.
2246 */
2247static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002248xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002249 const xmlChar *facetname, const xmlChar *val,
2250 const xmlChar *strval, void *value) {
2251 xmlSchemaFacetPtr facet;
2252 xmlSchemaTypePtr typ;
2253 int ret;
2254
2255 if ((type == NULL) || (strval == NULL))
2256 return(-1);
2257 typ = xmlSchemaGetPredefinedType(type,
2258 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2259 if (typ == NULL)
2260 return(-1);
2261
2262 facet = xmlSchemaNewFacet();
2263 if (facet == NULL)
2264 return(-1);
2265
2266 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2267 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2268 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2269 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2270 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2271 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2272 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2273 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2274 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2275 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2276 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2277 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2278 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2279 facet->type = XML_SCHEMA_FACET_PATTERN;
2280 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2281 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2282 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2283 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2284 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2285 facet->type = XML_SCHEMA_FACET_LENGTH;
2286 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2287 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2288 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2289 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2290 } else {
2291 xmlSchemaFreeFacet(facet);
2292 return(-1);
2293 }
2294 facet->value = xmlStrdup(val);
2295 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2296 if (ret != 0) {
2297 xmlSchemaFreeFacet(facet);
2298 return(-1);
2299 }
2300 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2301 xmlSchemaFreeFacet(facet);
2302 if (ret != 0)
2303 return(-1);
2304 return(0);
2305}
2306
2307/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002308 * xmlRelaxNGSchemaTypeCompare:
2309 * @data: data needed for the library
2310 * @type: the type name
2311 * @value1: the first value
2312 * @value2: the second value
2313 *
2314 * Compare two values accordingly a type from the W3C XMLSchema
2315 * Datatype library.
2316 *
2317 * Returns 1 if yes, 0 if no and -1 in case of error.
2318 */
2319static int
2320xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2321 const xmlChar *type ATTRIBUTE_UNUSED,
2322 const xmlChar *value1 ATTRIBUTE_UNUSED,
2323 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2324 TODO
2325 return(1);
2326}
2327
2328/**
2329 * xmlRelaxNGDefaultTypeHave:
2330 * @data: data needed for the library
2331 * @type: the type name
2332 *
2333 * Check if the given type is provided by
2334 * the default datatype library.
2335 *
2336 * Returns 1 if yes, 0 if no and -1 in case of error.
2337 */
2338static int
2339xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2340 if (type == NULL)
2341 return(-1);
2342 if (xmlStrEqual(type, BAD_CAST "string"))
2343 return(1);
2344 if (xmlStrEqual(type, BAD_CAST "token"))
2345 return(1);
2346 return(0);
2347}
2348
2349/**
2350 * xmlRelaxNGDefaultTypeCheck:
2351 * @data: data needed for the library
2352 * @type: the type name
2353 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002354 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002355 *
2356 * Check if the given type and value are validated by
2357 * the default datatype library.
2358 *
2359 * Returns 1 if yes, 0 if no and -1 in case of error.
2360 */
2361static int
2362xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2363 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002364 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002365 void **result ATTRIBUTE_UNUSED,
2366 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002367 if (value == NULL)
2368 return(-1);
2369 if (xmlStrEqual(type, BAD_CAST "string"))
2370 return(1);
2371 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002372 return(1);
2373 }
2374
2375 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002376}
2377
2378/**
2379 * xmlRelaxNGDefaultTypeCompare:
2380 * @data: data needed for the library
2381 * @type: the type name
2382 * @value1: the first value
2383 * @value2: the second value
2384 *
2385 * Compare two values accordingly a type from the default
2386 * datatype library.
2387 *
2388 * Returns 1 if yes, 0 if no and -1 in case of error.
2389 */
2390static int
2391xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2392 const xmlChar *type ATTRIBUTE_UNUSED,
2393 const xmlChar *value1 ATTRIBUTE_UNUSED,
2394 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002395 int ret = -1;
2396
2397 if (xmlStrEqual(type, BAD_CAST "string")) {
2398 ret = xmlStrEqual(value1, value2);
2399 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2400 if (!xmlStrEqual(value1, value2)) {
2401 xmlChar *nval, *nvalue;
2402
2403 /*
2404 * TODO: trivial optimizations are possible by
2405 * computing at compile-time
2406 */
2407 nval = xmlRelaxNGNormalize(NULL, value1);
2408 nvalue = xmlRelaxNGNormalize(NULL, value2);
2409
Daniel Veillardd4310742003-02-18 21:12:46 +00002410 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002411 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002412 else if (xmlStrEqual(nval, nvalue))
2413 ret = 1;
2414 else
2415 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002416 if (nval != NULL)
2417 xmlFree(nval);
2418 if (nvalue != NULL)
2419 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002420 } else
2421 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002422 }
2423 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002424}
2425
2426static int xmlRelaxNGTypeInitialized = 0;
2427static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2428
2429/**
2430 * xmlRelaxNGFreeTypeLibrary:
2431 * @lib: the type library structure
2432 * @namespace: the URI bound to the library
2433 *
2434 * Free the structure associated to the type library
2435 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002436static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002437xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2438 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2439 if (lib == NULL)
2440 return;
2441 if (lib->namespace != NULL)
2442 xmlFree((xmlChar *)lib->namespace);
2443 xmlFree(lib);
2444}
2445
2446/**
2447 * xmlRelaxNGRegisterTypeLibrary:
2448 * @namespace: the URI bound to the library
2449 * @data: data associated to the library
2450 * @have: the provide function
2451 * @check: the checking function
2452 * @comp: the comparison function
2453 *
2454 * Register a new type library
2455 *
2456 * Returns 0 in case of success and -1 in case of error.
2457 */
2458static int
2459xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2460 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002461 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2462 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002463 xmlRelaxNGTypeLibraryPtr lib;
2464 int ret;
2465
2466 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2467 (check == NULL) || (comp == NULL))
2468 return(-1);
2469 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2470 xmlGenericError(xmlGenericErrorContext,
2471 "Relax-NG types library '%s' already registered\n",
2472 namespace);
2473 return(-1);
2474 }
2475 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2476 if (lib == NULL) {
2477 xmlGenericError(xmlGenericErrorContext,
2478 "Relax-NG types library '%s' malloc() failed\n",
2479 namespace);
2480 return (-1);
2481 }
2482 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2483 lib->namespace = xmlStrdup(namespace);
2484 lib->data = data;
2485 lib->have = have;
2486 lib->comp = comp;
2487 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002488 lib->facet = facet;
2489 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002490 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2491 if (ret < 0) {
2492 xmlGenericError(xmlGenericErrorContext,
2493 "Relax-NG types library failed to register '%s'\n",
2494 namespace);
2495 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2496 return(-1);
2497 }
2498 return(0);
2499}
2500
2501/**
2502 * xmlRelaxNGInitTypes:
2503 *
2504 * Initilize the default type libraries.
2505 *
2506 * Returns 0 in case of success and -1 in case of error.
2507 */
2508static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002509xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002510 if (xmlRelaxNGTypeInitialized != 0)
2511 return(0);
2512 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2513 if (xmlRelaxNGRegisteredTypes == NULL) {
2514 xmlGenericError(xmlGenericErrorContext,
2515 "Failed to allocate sh table for Relax-NG types\n");
2516 return(-1);
2517 }
2518 xmlRelaxNGRegisterTypeLibrary(
2519 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2520 NULL,
2521 xmlRelaxNGSchemaTypeHave,
2522 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002523 xmlRelaxNGSchemaTypeCompare,
2524 xmlRelaxNGSchemaFacetCheck,
2525 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002526 xmlRelaxNGRegisterTypeLibrary(
2527 xmlRelaxNGNs,
2528 NULL,
2529 xmlRelaxNGDefaultTypeHave,
2530 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002531 xmlRelaxNGDefaultTypeCompare,
2532 NULL,
2533 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002534 xmlRelaxNGTypeInitialized = 1;
2535 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002536}
2537
2538/**
2539 * xmlRelaxNGCleanupTypes:
2540 *
2541 * Cleanup the default Schemas type library associated to RelaxNG
2542 */
2543void
2544xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002545 if (xmlRelaxNGTypeInitialized == 0)
2546 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002547 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002548 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2549 xmlRelaxNGFreeTypeLibrary);
2550 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002551}
2552
2553/************************************************************************
2554 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002555 * Compiling element content into regexp *
2556 * *
2557 * Sometime the element content can be compiled into a pure regexp, *
2558 * This allows a faster execution and streamability at that level *
2559 * *
2560 ************************************************************************/
2561
2562/**
2563 * xmlRelaxNGIsCompileable:
2564 * @define: the definition to check
2565 *
2566 * Check if a definition is nullable.
2567 *
2568 * Returns 1 if yes, 0 if no and -1 in case of error
2569 */
2570static int
2571xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2572 if (def == NULL) {
2573 return(-1);
2574 }
2575 switch(def->type) {
2576 case XML_RELAXNG_REF:
2577 case XML_RELAXNG_EXTERNALREF:
2578 case XML_RELAXNG_PARENTREF:
2579 case XML_RELAXNG_NOOP:
2580 case XML_RELAXNG_START:
2581 return(xmlRelaxNGIsCompileable(def->content));
2582 case XML_RELAXNG_TEXT:
2583 case XML_RELAXNG_DATATYPE:
2584 case XML_RELAXNG_LIST:
2585 case XML_RELAXNG_PARAM:
2586 case XML_RELAXNG_VALUE:
2587
2588 case XML_RELAXNG_EMPTY:
2589 case XML_RELAXNG_ELEMENT:
2590 return(1);
2591 case XML_RELAXNG_OPTIONAL:
2592 case XML_RELAXNG_ZEROORMORE:
2593 case XML_RELAXNG_ONEORMORE:
2594 case XML_RELAXNG_CHOICE:
2595 case XML_RELAXNG_GROUP:
2596 case XML_RELAXNG_DEF: {
2597 xmlRelaxNGDefinePtr list;
2598 int ret;
2599
2600 list = def->content;
2601 while (list != NULL) {
2602 ret = xmlRelaxNGIsCompileable(list);
2603 if (ret != 1)
2604 return(ret);
2605 list = list->next;
2606 }
2607 return(1);
2608 }
2609 case XML_RELAXNG_EXCEPT:
2610 case XML_RELAXNG_ATTRIBUTE:
2611 case XML_RELAXNG_INTERLEAVE:
2612 return(0);
2613 case XML_RELAXNG_NOT_ALLOWED:
2614 return(-1);
2615 }
2616 return(-1);
2617}
2618
2619/************************************************************************
2620 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002621 * Parsing functions *
2622 * *
2623 ************************************************************************/
2624
2625static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2626 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2627static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2628 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2629static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002630 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002631static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2632 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002633static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2634 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002635static int xmlRelaxNGParseGrammarContent(
2636 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002637static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2638 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2639 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002640static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2641 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002642static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2643 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002644
2645
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002646#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002647
2648/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002649 * xmlRelaxNGIsNullable:
2650 * @define: the definition to verify
2651 *
2652 * Check if a definition is nullable.
2653 *
2654 * Returns 1 if yes, 0 if no and -1 in case of error
2655 */
2656static int
2657xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2658 int ret;
2659 if (define == NULL)
2660 return(-1);
2661
Daniel Veillarde063f482003-03-21 16:53:17 +00002662 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002663 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00002664 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002665 return(0);
2666 switch (define->type) {
2667 case XML_RELAXNG_EMPTY:
2668 case XML_RELAXNG_TEXT:
2669 ret = 1; break;
2670 case XML_RELAXNG_NOOP:
2671 case XML_RELAXNG_DEF:
2672 case XML_RELAXNG_REF:
2673 case XML_RELAXNG_EXTERNALREF:
2674 case XML_RELAXNG_PARENTREF:
2675 case XML_RELAXNG_ONEORMORE:
2676 ret = xmlRelaxNGIsNullable(define->content);
2677 break;
2678 case XML_RELAXNG_EXCEPT:
2679 case XML_RELAXNG_NOT_ALLOWED:
2680 case XML_RELAXNG_ELEMENT:
2681 case XML_RELAXNG_DATATYPE:
2682 case XML_RELAXNG_PARAM:
2683 case XML_RELAXNG_VALUE:
2684 case XML_RELAXNG_LIST:
2685 case XML_RELAXNG_ATTRIBUTE:
2686 ret = 0; break;
2687 case XML_RELAXNG_CHOICE: {
2688 xmlRelaxNGDefinePtr list = define->content;
2689
2690 while (list != NULL) {
2691 ret = xmlRelaxNGIsNullable(list);
2692 if (ret != 0)
2693 goto done;
2694 list = list->next;
2695 }
2696 ret = 0; break;
2697 }
2698 case XML_RELAXNG_START:
2699 case XML_RELAXNG_INTERLEAVE:
2700 case XML_RELAXNG_GROUP: {
2701 xmlRelaxNGDefinePtr list = define->content;
2702
2703 while (list != NULL) {
2704 ret = xmlRelaxNGIsNullable(list);
2705 if (ret != 1)
2706 goto done;
2707 list = list->next;
2708 }
2709 return(1);
2710 }
2711 default:
2712 return(-1);
2713 }
2714done:
2715 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00002716 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002717 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00002718 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002719 return(ret);
2720}
2721
2722/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002723 * xmlRelaxNGIsBlank:
2724 * @str: a string
2725 *
2726 * Check if a string is ignorable c.f. 4.2. Whitespace
2727 *
2728 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2729 */
2730static int
2731xmlRelaxNGIsBlank(xmlChar *str) {
2732 if (str == NULL)
2733 return(1);
2734 while (*str != 0) {
2735 if (!(IS_BLANK(*str))) return(0);
2736 str++;
2737 }
2738 return(1);
2739}
2740
Daniel Veillard6eadf632003-01-23 18:29:16 +00002741/**
2742 * xmlRelaxNGGetDataTypeLibrary:
2743 * @ctxt: a Relax-NG parser context
2744 * @node: the current data or value element
2745 *
2746 * Applies algorithm from 4.3. datatypeLibrary attribute
2747 *
2748 * Returns the datatypeLibary value or NULL if not found
2749 */
2750static xmlChar *
2751xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2752 xmlNodePtr node) {
2753 xmlChar *ret, *escape;
2754
Daniel Veillard6eadf632003-01-23 18:29:16 +00002755 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2756 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2757 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002758 if (ret[0] == 0) {
2759 xmlFree(ret);
2760 return(NULL);
2761 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002762 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002763 if (escape == NULL) {
2764 return(ret);
2765 }
2766 xmlFree(ret);
2767 return(escape);
2768 }
2769 }
2770 node = node->parent;
2771 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002772 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2773 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002774 if (ret[0] == 0) {
2775 xmlFree(ret);
2776 return(NULL);
2777 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002778 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2779 if (escape == NULL) {
2780 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002781 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002782 xmlFree(ret);
2783 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002784 }
2785 node = node->parent;
2786 }
2787 return(NULL);
2788}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002789
2790/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002791 * xmlRelaxNGParseValue:
2792 * @ctxt: a Relax-NG parser context
2793 * @node: the data node.
2794 *
2795 * parse the content of a RelaxNG value node.
2796 *
2797 * Returns the definition pointer or NULL in case of error
2798 */
2799static xmlRelaxNGDefinePtr
2800xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2801 xmlRelaxNGDefinePtr def = NULL;
2802 xmlRelaxNGTypeLibraryPtr lib;
2803 xmlChar *type;
2804 xmlChar *library;
2805 int tmp;
2806
Daniel Veillardfd573f12003-03-16 17:52:32 +00002807 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002808 if (def == NULL)
2809 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002810 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002811
2812 type = xmlGetProp(node, BAD_CAST "type");
2813 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002814 xmlRelaxNGNormExtSpace(type);
2815 if (xmlValidateNCName(type, 0)) {
2816 if (ctxt->error != NULL)
2817 ctxt->error(ctxt->userData,
2818 "value type '%s' is not an NCName\n",
2819 type);
2820 ctxt->nbErrors++;
2821 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002822 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2823 if (library == NULL)
2824 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2825
2826 def->name = type;
2827 def->ns = library;
2828
2829 lib = (xmlRelaxNGTypeLibraryPtr)
2830 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2831 if (lib == NULL) {
2832 if (ctxt->error != NULL)
2833 ctxt->error(ctxt->userData,
2834 "Use of unregistered type library '%s'\n",
2835 library);
2836 ctxt->nbErrors++;
2837 def->data = NULL;
2838 } else {
2839 def->data = lib;
2840 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002841 if (ctxt->error != NULL)
2842 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002843 "Internal error with type library '%s': no 'have'\n",
2844 library);
2845 ctxt->nbErrors++;
2846 } else {
2847 tmp = lib->have(lib->data, def->name);
2848 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002849 if (ctxt->error != NULL)
2850 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002851 "Error type '%s' is not exported by type library '%s'\n",
2852 def->name, library);
2853 ctxt->nbErrors++;
2854 }
2855 }
2856 }
2857 }
2858 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002859 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002860 } else if (((node->children->type != XML_TEXT_NODE) &&
2861 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002862 (node->children->next != NULL)) {
2863 if (ctxt->error != NULL)
2864 ctxt->error(ctxt->userData,
2865 "Expecting a single text value for <value>content\n");
2866 ctxt->nbErrors++;
2867 } else {
2868 def->value = xmlNodeGetContent(node);
2869 if (def->value == NULL) {
2870 if (ctxt->error != NULL)
2871 ctxt->error(ctxt->userData,
2872 "Element <value> has no content\n");
2873 ctxt->nbErrors++;
2874 }
2875 }
2876 /* TODO check ahead of time that the value is okay per the type */
2877 return(def);
2878}
2879
2880/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002881 * xmlRelaxNGParseData:
2882 * @ctxt: a Relax-NG parser context
2883 * @node: the data node.
2884 *
2885 * parse the content of a RelaxNG data node.
2886 *
2887 * Returns the definition pointer or NULL in case of error
2888 */
2889static xmlRelaxNGDefinePtr
2890xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002891 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002892 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002893 xmlRelaxNGTypeLibraryPtr lib;
2894 xmlChar *type;
2895 xmlChar *library;
2896 xmlNodePtr content;
2897 int tmp;
2898
2899 type = xmlGetProp(node, BAD_CAST "type");
2900 if (type == NULL) {
2901 if (ctxt->error != NULL)
2902 ctxt->error(ctxt->userData,
2903 "data has no type\n");
2904 ctxt->nbErrors++;
2905 return(NULL);
2906 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002907 xmlRelaxNGNormExtSpace(type);
2908 if (xmlValidateNCName(type, 0)) {
2909 if (ctxt->error != NULL)
2910 ctxt->error(ctxt->userData,
2911 "data type '%s' is not an NCName\n",
2912 type);
2913 ctxt->nbErrors++;
2914 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002915 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2916 if (library == NULL)
2917 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2918
Daniel Veillardfd573f12003-03-16 17:52:32 +00002919 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002920 if (def == NULL) {
2921 xmlFree(type);
2922 return(NULL);
2923 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002924 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002925 def->name = type;
2926 def->ns = library;
2927
2928 lib = (xmlRelaxNGTypeLibraryPtr)
2929 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2930 if (lib == NULL) {
2931 if (ctxt->error != NULL)
2932 ctxt->error(ctxt->userData,
2933 "Use of unregistered type library '%s'\n",
2934 library);
2935 ctxt->nbErrors++;
2936 def->data = NULL;
2937 } else {
2938 def->data = lib;
2939 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002940 if (ctxt->error != NULL)
2941 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002942 "Internal error with type library '%s': no 'have'\n",
2943 library);
2944 ctxt->nbErrors++;
2945 } else {
2946 tmp = lib->have(lib->data, def->name);
2947 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002948 if (ctxt->error != NULL)
2949 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002950 "Error type '%s' is not exported by type library '%s'\n",
2951 def->name, library);
2952 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002953 } else if ((xmlStrEqual(library, BAD_CAST
2954 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
2955 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
2956 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
2957 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002958 }
2959 }
2960 }
2961 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002962
2963 /*
2964 * Handle optional params
2965 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002966 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002967 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2968 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002969 if (xmlStrEqual(library,
2970 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2971 if (ctxt->error != NULL)
2972 ctxt->error(ctxt->userData,
2973 "Type library '%s' does not allow type parameters\n",
2974 library);
2975 ctxt->nbErrors++;
2976 content = content->next;
2977 while ((content != NULL) &&
2978 (xmlStrEqual(content->name, BAD_CAST "param")))
2979 content = content->next;
2980 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002981 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002982 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002983 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002984 param->name = xmlGetProp(content, BAD_CAST "name");
2985 if (param->name == NULL) {
2986 if (ctxt->error != NULL)
2987 ctxt->error(ctxt->userData,
2988 "param has no name\n");
2989 ctxt->nbErrors++;
2990 }
2991 param->value = xmlNodeGetContent(content);
2992 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002993 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002994 } else {
2995 lastparam->next = param;
2996 lastparam = param;
2997 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002998 if (lib != NULL) {
2999 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003000 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003001 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003002 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003003 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003004 /*
3005 * Handle optional except
3006 */
3007 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3008 xmlNodePtr child;
3009 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3010
Daniel Veillardfd573f12003-03-16 17:52:32 +00003011 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003012 if (except == NULL) {
3013 return(def);
3014 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003015 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003016 child = content->children;
3017 if (last == NULL) {
3018 def->content = except;
3019 } else {
3020 last->next = except;
3021 }
3022 if (child == NULL) {
3023 if (ctxt->error != NULL)
3024 ctxt->error(ctxt->userData,
3025 "except has no content\n");
3026 ctxt->nbErrors++;
3027 }
3028 while (child != NULL) {
3029 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3030 if (tmp2 != NULL) {
3031 if (last2 == NULL) {
3032 except->content = last2 = tmp2;
3033 } else {
3034 last2->next = tmp2;
3035 last2 = tmp2;
3036 }
3037 }
3038 child = child->next;
3039 }
3040 content = content->next;
3041 }
3042 /*
3043 * Check there is no unhandled data
3044 */
3045 if (content != NULL) {
3046 if (ctxt->error != NULL)
3047 ctxt->error(ctxt->userData,
3048 "Element data has unexpected content %s\n", content->name);
3049 ctxt->nbErrors++;
3050 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003051
3052 return(def);
3053}
3054
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003055static const xmlChar *invalidName = BAD_CAST "\1";
3056
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003057/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003058 * xmlRelaxNGCompareNameClasses:
3059 * @defs1: the first element/attribute defs
3060 * @defs2: the second element/attribute defs
3061 * @name: the restriction on the name
3062 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003063 *
3064 * Compare the 2 lists of element definitions. The comparison is
3065 * that if both lists do not accept the same QNames, it returns 1
3066 * If the 2 lists can accept the same QName the comparison returns 0
3067 *
3068 * Returns 1 disttinct, 0 if equal
3069 */
3070static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003071xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3072 xmlRelaxNGDefinePtr def2) {
3073 int ret = 1;
3074 xmlNode node;
3075 xmlNs ns;
3076 xmlRelaxNGValidCtxt ctxt;
3077 ctxt.flags = FLAGS_IGNORABLE;
3078
Daniel Veillard42f12e92003-03-07 18:32:59 +00003079 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3080
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003081 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3082 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3083 if (def2->type == XML_RELAXNG_TEXT)
3084 return(1);
3085 if (def1->name != NULL) {
3086 node.name = def1->name;
3087 } else {
3088 node.name = invalidName;
3089 }
3090 node.ns = &ns;
3091 if (def1->ns != NULL) {
3092 if (def1->ns[0] == 0) {
3093 node.ns = NULL;
3094 } else {
3095 ns.href = def1->ns;
3096 }
3097 } else {
3098 ns.href = invalidName;
3099 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003100 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003101 if (def1->nameClass != NULL) {
3102 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3103 } else {
3104 ret = 0;
3105 }
3106 } else {
3107 ret = 1;
3108 }
3109 } else if (def1->type == XML_RELAXNG_TEXT) {
3110 if (def2->type == XML_RELAXNG_TEXT)
3111 return(0);
3112 return(1);
3113 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003114 TODO
3115 ret = 0;
3116 } else {
3117 TODO
3118 ret = 0;
3119 }
3120 if (ret == 0)
3121 return(ret);
3122 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3123 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3124 if (def2->name != NULL) {
3125 node.name = def2->name;
3126 } else {
3127 node.name = invalidName;
3128 }
3129 node.ns = &ns;
3130 if (def2->ns != NULL) {
3131 if (def2->ns[0] == 0) {
3132 node.ns = NULL;
3133 } else {
3134 ns.href = def2->ns;
3135 }
3136 } else {
3137 ns.href = invalidName;
3138 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003139 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003140 if (def2->nameClass != NULL) {
3141 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3142 } else {
3143 ret = 0;
3144 }
3145 } else {
3146 ret = 1;
3147 }
3148 } else {
3149 TODO
3150 ret = 0;
3151 }
3152
3153 return(ret);
3154}
3155
3156/**
3157 * xmlRelaxNGCompareElemDefLists:
3158 * @ctxt: a Relax-NG parser context
3159 * @defs1: the first list of element/attribute defs
3160 * @defs2: the second list of element/attribute defs
3161 *
3162 * Compare the 2 lists of element or attribute definitions. The comparison
3163 * is that if both lists do not accept the same QNames, it returns 1
3164 * If the 2 lists can accept the same QName the comparison returns 0
3165 *
3166 * Returns 1 disttinct, 0 if equal
3167 */
3168static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003169xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3170 xmlRelaxNGDefinePtr *def1,
3171 xmlRelaxNGDefinePtr *def2) {
3172 xmlRelaxNGDefinePtr *basedef2 = def2;
3173
Daniel Veillard154877e2003-01-30 12:17:05 +00003174 if ((def1 == NULL) || (def2 == NULL))
3175 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003176 if ((*def1 == NULL) || (*def2 == NULL))
3177 return(1);
3178 while (*def1 != NULL) {
3179 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003180 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3181 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003182 def2++;
3183 }
3184 def2 = basedef2;
3185 def1++;
3186 }
3187 return(1);
3188}
3189
3190/**
3191 * xmlRelaxNGGetElements:
3192 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003193 * @def: the definition definition
3194 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003195 *
3196 * Compute the list of top elements a definition can generate
3197 *
3198 * Returns a list of elements or NULL if none was found.
3199 */
3200static xmlRelaxNGDefinePtr *
3201xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003202 xmlRelaxNGDefinePtr def,
3203 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003204 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003205 int len = 0;
3206 int max = 0;
3207
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003208 /*
3209 * Don't run that check in case of error. Infinite recursion
3210 * becomes possible.
3211 */
3212 if (ctxt->nbErrors != 0)
3213 return(NULL);
3214
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003215 parent = NULL;
3216 cur = def;
3217 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003218 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3219 (cur->type == XML_RELAXNG_TEXT))) ||
3220 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003221 if (ret == NULL) {
3222 max = 10;
3223 ret = (xmlRelaxNGDefinePtr *)
3224 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3225 if (ret == NULL) {
3226 if (ctxt->error != NULL)
3227 ctxt->error(ctxt->userData,
3228 "Out of memory in element search\n");
3229 ctxt->nbErrors++;
3230 return(NULL);
3231 }
3232 } else if (max <= len) {
3233 max *= 2;
3234 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3235 if (ret == NULL) {
3236 if (ctxt->error != NULL)
3237 ctxt->error(ctxt->userData,
3238 "Out of memory in element search\n");
3239 ctxt->nbErrors++;
3240 return(NULL);
3241 }
3242 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003243 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003244 ret[len] = NULL;
3245 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3246 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3247 (cur->type == XML_RELAXNG_GROUP) ||
3248 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003249 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3250 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003251 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003252 (cur->type == XML_RELAXNG_REF) ||
3253 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003254 /*
3255 * Don't go within elements or attributes or string values.
3256 * Just gather the element top list
3257 */
3258 if (cur->content != NULL) {
3259 parent = cur;
3260 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003261 tmp = cur;
3262 while (tmp != NULL) {
3263 tmp->parent = parent;
3264 tmp = tmp->next;
3265 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003266 continue;
3267 }
3268 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003269 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003270 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003271 if (cur->next != NULL) {
3272 cur = cur->next;
3273 continue;
3274 }
3275 do {
3276 cur = cur->parent;
3277 if (cur == NULL) break;
3278 if (cur == def) return(ret);
3279 if (cur->next != NULL) {
3280 cur = cur->next;
3281 break;
3282 }
3283 } while (cur != NULL);
3284 }
3285 return(ret);
3286}
3287
3288/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003289 * xmlRelaxNGCheckChoiceDeterminism:
3290 * @ctxt: a Relax-NG parser context
3291 * @def: the choice definition
3292 *
3293 * Also used to find indeterministic pattern in choice
3294 */
3295static void
3296xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3297 xmlRelaxNGDefinePtr def) {
3298 xmlRelaxNGDefinePtr **list;
3299 xmlRelaxNGDefinePtr cur;
3300 int nbchild = 0, i, j, ret;
3301 int is_nullable = 0;
3302 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003303 xmlHashTablePtr triage = NULL;
3304 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003305
3306 if ((def == NULL) ||
3307 (def->type != XML_RELAXNG_CHOICE))
3308 return;
3309
Daniel Veillarde063f482003-03-21 16:53:17 +00003310 if (def->dflags & IS_PROCESSED)
3311 return;
3312
Daniel Veillardfd573f12003-03-16 17:52:32 +00003313 /*
3314 * Don't run that check in case of error. Infinite recursion
3315 * becomes possible.
3316 */
3317 if (ctxt->nbErrors != 0)
3318 return;
3319
3320 is_nullable = xmlRelaxNGIsNullable(def);
3321
3322 cur = def->content;
3323 while (cur != NULL) {
3324 nbchild++;
3325 cur = cur->next;
3326 }
3327
3328 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3329 sizeof(xmlRelaxNGDefinePtr *));
3330 if (list == NULL) {
3331 if (ctxt->error != NULL)
3332 ctxt->error(ctxt->userData,
3333 "Out of memory in choice computation\n");
3334 ctxt->nbErrors++;
3335 return;
3336 }
3337 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003338 /*
3339 * a bit strong but safe
3340 */
3341 if (is_nullable == 0) {
3342 triage = xmlHashCreate(10);
3343 } else {
3344 is_triable = 0;
3345 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003346 cur = def->content;
3347 while (cur != NULL) {
3348 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003349 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3350 is_triable = 0;
3351 } else if (is_triable == 1) {
3352 xmlRelaxNGDefinePtr *tmp;
3353 int res;
3354
3355 tmp = list[i];
3356 while ((*tmp != NULL) && (is_triable == 1)) {
3357 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3358 res = xmlHashAddEntry2(triage,
3359 BAD_CAST "#text", NULL,
3360 (void *)cur);
3361 if (res != 0)
3362 is_triable = -1;
3363 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3364 ((*tmp)->name != NULL)) {
3365 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3366 res = xmlHashAddEntry2(triage,
3367 (*tmp)->name, NULL,
3368 (void *)cur);
3369 else
3370 res = xmlHashAddEntry2(triage,
3371 (*tmp)->name, (*tmp)->ns,
3372 (void *)cur);
3373 if (res != 0)
3374 is_triable = -1;
3375 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3376 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3377 res = xmlHashAddEntry2(triage,
3378 BAD_CAST "#any", NULL,
3379 (void *)cur);
3380 else
3381 res = xmlHashAddEntry2(triage,
3382 BAD_CAST "#any", (*tmp)->ns,
3383 (void *)cur);
3384 if (res != 0)
3385 is_triable = -1;
3386 } else {
3387 is_triable = -1;
3388 }
3389 tmp++;
3390 }
3391 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003392 i++;
3393 cur = cur->next;
3394 }
3395
3396 for (i = 0;i < nbchild;i++) {
3397 if (list[i] == NULL)
3398 continue;
3399 for (j = 0;j < i;j++) {
3400 if (list[j] == NULL)
3401 continue;
3402 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3403 if (ret == 0) {
3404 is_indeterminist = 1;
3405 }
3406 }
3407 }
3408 for (i = 0;i < nbchild;i++) {
3409 if (list[i] != NULL)
3410 xmlFree(list[i]);
3411 }
3412
3413 xmlFree(list);
3414 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003415 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003416 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003417 if (is_triable == 1) {
3418 def->dflags |= IS_TRIABLE;
3419 def->data = triage;
3420 } else if (triage != NULL) {
3421 xmlHashFree(triage, NULL);
3422 }
3423 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003424}
3425
3426/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003427 * xmlRelaxNGCheckGroupAttrs:
3428 * @ctxt: a Relax-NG parser context
3429 * @def: the group definition
3430 *
3431 * Detects violations of rule 7.3
3432 */
3433static void
3434xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3435 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003436 xmlRelaxNGDefinePtr **list;
3437 xmlRelaxNGDefinePtr cur;
3438 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003439
3440 if ((def == NULL) ||
3441 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003442 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003443 return;
3444
Daniel Veillarde063f482003-03-21 16:53:17 +00003445 if (def->dflags & IS_PROCESSED)
3446 return;
3447
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003448 /*
3449 * Don't run that check in case of error. Infinite recursion
3450 * becomes possible.
3451 */
3452 if (ctxt->nbErrors != 0)
3453 return;
3454
Daniel Veillardfd573f12003-03-16 17:52:32 +00003455 cur = def->attrs;
3456 while (cur != NULL) {
3457 nbchild++;
3458 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003459 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003460 cur = def->content;
3461 while (cur != NULL) {
3462 nbchild++;
3463 cur = cur->next;
3464 }
3465
3466 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3467 sizeof(xmlRelaxNGDefinePtr *));
3468 if (list == NULL) {
3469 if (ctxt->error != NULL)
3470 ctxt->error(ctxt->userData,
3471 "Out of memory in group computation\n");
3472 ctxt->nbErrors++;
3473 return;
3474 }
3475 i = 0;
3476 cur = def->attrs;
3477 while (cur != NULL) {
3478 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3479 i++;
3480 cur = cur->next;
3481 }
3482 cur = def->content;
3483 while (cur != NULL) {
3484 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3485 i++;
3486 cur = cur->next;
3487 }
3488
3489 for (i = 0;i < nbchild;i++) {
3490 if (list[i] == NULL)
3491 continue;
3492 for (j = 0;j < i;j++) {
3493 if (list[j] == NULL)
3494 continue;
3495 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3496 if (ret == 0) {
3497 if (ctxt->error != NULL)
3498 ctxt->error(ctxt->userData,
3499 "Attributes conflicts in group\n");
3500 ctxt->nbErrors++;
3501 }
3502 }
3503 }
3504 for (i = 0;i < nbchild;i++) {
3505 if (list[i] != NULL)
3506 xmlFree(list[i]);
3507 }
3508
3509 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003510 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003511}
3512
3513/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003514 * xmlRelaxNGComputeInterleaves:
3515 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003516 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003517 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003518 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003519 * A lot of work for preprocessing interleave definitions
3520 * is potentially needed to get a decent execution speed at runtime
3521 * - trying to get a total order on the element nodes generated
3522 * by the interleaves, order the list of interleave definitions
3523 * following that order.
3524 * - if <text/> is used to handle mixed content, it is better to
3525 * flag this in the define and simplify the runtime checking
3526 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003527 */
3528static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003529xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3530 xmlRelaxNGParserCtxtPtr ctxt,
3531 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003532 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003533
Daniel Veillardfd573f12003-03-16 17:52:32 +00003534 xmlRelaxNGPartitionPtr partitions = NULL;
3535 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3536 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003537 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003538 int nbgroups = 0;
3539 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003540 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003541 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003542
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003543 /*
3544 * Don't run that check in case of error. Infinite recursion
3545 * becomes possible.
3546 */
3547 if (ctxt->nbErrors != 0)
3548 return;
3549
Daniel Veillardfd573f12003-03-16 17:52:32 +00003550#ifdef DEBUG_INTERLEAVE
3551 xmlGenericError(xmlGenericErrorContext,
3552 "xmlRelaxNGComputeInterleaves(%s)\n",
3553 name);
3554#endif
3555 cur = def->content;
3556 while (cur != NULL) {
3557 nbchild++;
3558 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003559 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003560
3561#ifdef DEBUG_INTERLEAVE
3562 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3563#endif
3564 groups = (xmlRelaxNGInterleaveGroupPtr *)
3565 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3566 if (groups == NULL)
3567 goto error;
3568 cur = def->content;
3569 while (cur != NULL) {
3570 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3571 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3572 if (groups[nbgroups] == NULL)
3573 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003574 if (cur->type == XML_RELAXNG_TEXT)
3575 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003576 groups[nbgroups]->rule = cur;
3577 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3578 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3579 nbgroups++;
3580 cur = cur->next;
3581 }
3582#ifdef DEBUG_INTERLEAVE
3583 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3584#endif
3585
3586 /*
3587 * Let's check that all rules makes a partitions according to 7.4
3588 */
3589 partitions = (xmlRelaxNGPartitionPtr)
3590 xmlMalloc(sizeof(xmlRelaxNGPartition));
3591 if (partitions == NULL)
3592 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00003593 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00003594 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003595 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003596 for (i = 0;i < nbgroups;i++) {
3597 group = groups[i];
3598 for (j = i+1;j < nbgroups;j++) {
3599 if (groups[j] == NULL)
3600 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003601
Daniel Veillardfd573f12003-03-16 17:52:32 +00003602 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3603 groups[j]->defs);
3604 if (ret == 0) {
3605 if (ctxt->error != NULL)
3606 ctxt->error(ctxt->userData,
3607 "Element or text conflicts in interleave\n");
3608 ctxt->nbErrors++;
3609 }
3610 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3611 groups[j]->attrs);
3612 if (ret == 0) {
3613 if (ctxt->error != NULL)
3614 ctxt->error(ctxt->userData,
3615 "Attributes conflicts in interleave\n");
3616 ctxt->nbErrors++;
3617 }
3618 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003619 tmp = group->defs;
3620 if ((tmp != NULL) && (*tmp != NULL)) {
3621 while (*tmp != NULL) {
3622 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3623 res = xmlHashAddEntry2(partitions->triage,
3624 BAD_CAST "#text", NULL,
3625 (void *)(i + 1));
3626 if (res != 0)
3627 is_determinist = -1;
3628 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3629 ((*tmp)->name != NULL)) {
3630 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3631 res = xmlHashAddEntry2(partitions->triage,
3632 (*tmp)->name, NULL,
3633 (void *)(i + 1));
3634 else
3635 res = xmlHashAddEntry2(partitions->triage,
3636 (*tmp)->name, (*tmp)->ns,
3637 (void *)(i + 1));
3638 if (res != 0)
3639 is_determinist = -1;
3640 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3641 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3642 res = xmlHashAddEntry2(partitions->triage,
3643 BAD_CAST "#any", NULL,
3644 (void *)(i + 1));
3645 else
3646 res = xmlHashAddEntry2(partitions->triage,
3647 BAD_CAST "#any", (*tmp)->ns,
3648 (void *)(i + 1));
3649 if ((*tmp)->nameClass != NULL)
3650 is_determinist = 2;
3651 if (res != 0)
3652 is_determinist = -1;
3653 } else {
3654 is_determinist = -1;
3655 }
3656 tmp++;
3657 }
3658 } else {
3659 is_determinist = 0;
3660 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003661 }
3662 partitions->groups = groups;
3663
3664 /*
3665 * and save the partition list back in the def
3666 */
3667 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003668 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003669 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003670 if (is_determinist == 1)
3671 partitions->flags = IS_DETERMINIST;
3672 if (is_determinist == 2)
3673 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003674 return;
3675
3676error:
3677 if (ctxt->error != NULL)
3678 ctxt->error(ctxt->userData,
3679 "Out of memory in interleave computation\n");
3680 ctxt->nbErrors++;
3681 if (groups != NULL) {
3682 for (i = 0;i < nbgroups;i++)
3683 if (groups[i] != NULL) {
3684 if (groups[i]->defs != NULL)
3685 xmlFree(groups[i]->defs);
3686 xmlFree(groups[i]);
3687 }
3688 xmlFree(groups);
3689 }
3690 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003691}
3692
3693/**
3694 * xmlRelaxNGParseInterleave:
3695 * @ctxt: a Relax-NG parser context
3696 * @node: the data node.
3697 *
3698 * parse the content of a RelaxNG interleave node.
3699 *
3700 * Returns the definition pointer or NULL in case of error
3701 */
3702static xmlRelaxNGDefinePtr
3703xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3704 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003705 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003706 xmlNodePtr child;
3707
Daniel Veillardfd573f12003-03-16 17:52:32 +00003708 def = xmlRelaxNGNewDefine(ctxt, node);
3709 if (def == NULL) {
3710 return(NULL);
3711 }
3712 def->type = XML_RELAXNG_INTERLEAVE;
3713
3714 if (ctxt->interleaves == NULL)
3715 ctxt->interleaves = xmlHashCreate(10);
3716 if (ctxt->interleaves == NULL) {
3717 if (ctxt->error != NULL)
3718 ctxt->error(ctxt->userData,
3719 "Failed to create interleaves hash table\n");
3720 ctxt->nbErrors++;
3721 } else {
3722 char name[32];
3723
3724 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3725 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3726 if (ctxt->error != NULL)
3727 ctxt->error(ctxt->userData,
3728 "Failed to add %s to hash table\n", name);
3729 ctxt->nbErrors++;
3730 }
3731 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003732 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003733 if (child == NULL) {
3734 if (ctxt->error != NULL)
3735 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3736 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003737 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003738 while (child != NULL) {
3739 if (IS_RELAXNG(child, "element")) {
3740 cur = xmlRelaxNGParseElement(ctxt, child);
3741 } else {
3742 cur = xmlRelaxNGParsePattern(ctxt, child);
3743 }
3744 if (cur != NULL) {
3745 cur->parent = def;
3746 if (last == NULL) {
3747 def->content = last = cur;
3748 } else {
3749 last->next = cur;
3750 last = cur;
3751 }
3752 }
3753 child = child->next;
3754 }
3755
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003756 return(def);
3757}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003758
3759/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003760 * xmlRelaxNGParseInclude:
3761 * @ctxt: a Relax-NG parser context
3762 * @node: the include node
3763 *
3764 * Integrate the content of an include node in the current grammar
3765 *
3766 * Returns 0 in case of success or -1 in case of error
3767 */
3768static int
3769xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3770 xmlRelaxNGIncludePtr incl;
3771 xmlNodePtr root;
3772 int ret = 0, tmp;
3773
3774 incl = node->_private;
3775 if (incl == NULL) {
3776 if (ctxt->error != NULL)
3777 ctxt->error(ctxt->userData,
3778 "Include node has no data\n");
3779 ctxt->nbErrors++;
3780 return(-1);
3781 }
3782 root = xmlDocGetRootElement(incl->doc);
3783 if (root == NULL) {
3784 if (ctxt->error != NULL)
3785 ctxt->error(ctxt->userData,
3786 "Include document is empty\n");
3787 ctxt->nbErrors++;
3788 return(-1);
3789 }
3790 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3791 if (ctxt->error != NULL)
3792 ctxt->error(ctxt->userData,
3793 "Include document root is not a grammar\n");
3794 ctxt->nbErrors++;
3795 return(-1);
3796 }
3797
3798 /*
3799 * Merge the definition from both the include and the internal list
3800 */
3801 if (root->children != NULL) {
3802 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3803 if (tmp != 0)
3804 ret = -1;
3805 }
3806 if (node->children != NULL) {
3807 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3808 if (tmp != 0)
3809 ret = -1;
3810 }
3811 return(ret);
3812}
3813
3814/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003815 * xmlRelaxNGParseDefine:
3816 * @ctxt: a Relax-NG parser context
3817 * @node: the define node
3818 *
3819 * parse the content of a RelaxNG define element node.
3820 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003821 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003822 */
3823static int
3824xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3825 xmlChar *name;
3826 int ret = 0, tmp;
3827 xmlRelaxNGDefinePtr def;
3828 const xmlChar *olddefine;
3829
3830 name = xmlGetProp(node, BAD_CAST "name");
3831 if (name == NULL) {
3832 if (ctxt->error != NULL)
3833 ctxt->error(ctxt->userData,
3834 "define has no name\n");
3835 ctxt->nbErrors++;
3836 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003837 xmlRelaxNGNormExtSpace(name);
3838 if (xmlValidateNCName(name, 0)) {
3839 if (ctxt->error != NULL)
3840 ctxt->error(ctxt->userData,
3841 "define name '%s' is not an NCName\n",
3842 name);
3843 ctxt->nbErrors++;
3844 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003845 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003846 if (def == NULL) {
3847 xmlFree(name);
3848 return(-1);
3849 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003850 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003851 def->name = name;
3852 if (node->children == NULL) {
3853 if (ctxt->error != NULL)
3854 ctxt->error(ctxt->userData,
3855 "define has no children\n");
3856 ctxt->nbErrors++;
3857 } else {
3858 olddefine = ctxt->define;
3859 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003860 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003861 ctxt->define = olddefine;
3862 }
3863 if (ctxt->grammar->defs == NULL)
3864 ctxt->grammar->defs = xmlHashCreate(10);
3865 if (ctxt->grammar->defs == NULL) {
3866 if (ctxt->error != NULL)
3867 ctxt->error(ctxt->userData,
3868 "Could not create definition hash\n");
3869 ctxt->nbErrors++;
3870 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003871 } else {
3872 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3873 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003874 xmlRelaxNGDefinePtr prev;
3875
3876 prev = xmlHashLookup(ctxt->grammar->defs, name);
3877 if (prev == NULL) {
3878 if (ctxt->error != NULL)
3879 ctxt->error(ctxt->userData,
3880 "Internal error on define aggregation of %s\n",
3881 name);
3882 ctxt->nbErrors++;
3883 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003884 } else {
3885 while (prev->nextHash != NULL)
3886 prev = prev->nextHash;
3887 prev->nextHash = def;
3888 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003889 }
3890 }
3891 }
3892 return(ret);
3893}
3894
3895/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003896 * xmlRelaxNGProcessExternalRef:
3897 * @ctxt: the parser context
3898 * @node: the externlRef node
3899 *
3900 * Process and compile an externlRef node
3901 *
3902 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3903 */
3904static xmlRelaxNGDefinePtr
3905xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3906 xmlRelaxNGDocumentPtr docu;
3907 xmlNodePtr root, tmp;
3908 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003909 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003910 xmlRelaxNGDefinePtr def;
3911
3912 docu = node->_private;
3913 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003914 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003915 if (def == NULL)
3916 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003917 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003918
3919 if (docu->content == NULL) {
3920 /*
3921 * Then do the parsing for good
3922 */
3923 root = xmlDocGetRootElement(docu->doc);
3924 if (root == NULL) {
3925 if (ctxt->error != NULL)
3926 ctxt->error(ctxt->userData,
3927 "xmlRelaxNGParse: %s is empty\n",
3928 ctxt->URL);
3929 ctxt->nbErrors++;
3930 return (NULL);
3931 }
3932 /*
3933 * ns transmission rules
3934 */
3935 ns = xmlGetProp(root, BAD_CAST "ns");
3936 if (ns == NULL) {
3937 tmp = node;
3938 while ((tmp != NULL) &&
3939 (tmp->type == XML_ELEMENT_NODE)) {
3940 ns = xmlGetProp(tmp, BAD_CAST "ns");
3941 if (ns != NULL) {
3942 break;
3943 }
3944 tmp = tmp->parent;
3945 }
3946 if (ns != NULL) {
3947 xmlSetProp(root, BAD_CAST "ns", ns);
3948 newNs = 1;
3949 xmlFree(ns);
3950 }
3951 } else {
3952 xmlFree(ns);
3953 }
3954
3955 /*
3956 * Parsing to get a precompiled schemas.
3957 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003958 oldflags = ctxt->flags;
3959 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003960 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003961 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003962 if ((docu->schema != NULL) &&
3963 (docu->schema->topgrammar != NULL)) {
3964 docu->content = docu->schema->topgrammar->start;
3965 }
3966
3967 /*
3968 * the externalRef may be reused in a different ns context
3969 */
3970 if (newNs == 1) {
3971 xmlUnsetProp(root, BAD_CAST "ns");
3972 }
3973 }
3974 def->content = docu->content;
3975 } else {
3976 def = NULL;
3977 }
3978 return(def);
3979}
3980
3981/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003982 * xmlRelaxNGParsePattern:
3983 * @ctxt: a Relax-NG parser context
3984 * @node: the pattern node.
3985 *
3986 * parse the content of a RelaxNG pattern node.
3987 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003988 * Returns the definition pointer or NULL in case of error or if no
3989 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003990 */
3991static xmlRelaxNGDefinePtr
3992xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3993 xmlRelaxNGDefinePtr def = NULL;
3994
Daniel Veillardd2298792003-02-14 16:54:11 +00003995 if (node == NULL) {
3996 return(NULL);
3997 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003998 if (IS_RELAXNG(node, "element")) {
3999 def = xmlRelaxNGParseElement(ctxt, node);
4000 } else if (IS_RELAXNG(node, "attribute")) {
4001 def = xmlRelaxNGParseAttribute(ctxt, node);
4002 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004003 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004004 if (def == NULL)
4005 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004006 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004007 if (node->children != NULL) {
4008 if (ctxt->error != NULL)
4009 ctxt->error(ctxt->userData, "empty: had a child node\n");
4010 ctxt->nbErrors++;
4011 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004012 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004013 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004014 if (def == NULL)
4015 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004016 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004017 if (node->children != NULL) {
4018 if (ctxt->error != NULL)
4019 ctxt->error(ctxt->userData, "text: had a child node\n");
4020 ctxt->nbErrors++;
4021 }
4022 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004023 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004024 if (def == NULL)
4025 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004026 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004027 if (node->children == NULL) {
4028 if (ctxt->error != NULL)
4029 ctxt->error(ctxt->userData,
4030 "Element %s is empty\n", node->name);
4031 ctxt->nbErrors++;
4032 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004033 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004034 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004035 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004036 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004037 if (def == NULL)
4038 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004039 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004040 if (node->children == NULL) {
4041 if (ctxt->error != NULL)
4042 ctxt->error(ctxt->userData,
4043 "Element %s is empty\n", node->name);
4044 ctxt->nbErrors++;
4045 } else {
4046 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4047 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004048 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004049 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004050 if (def == NULL)
4051 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004052 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004053 if (node->children == NULL) {
4054 if (ctxt->error != NULL)
4055 ctxt->error(ctxt->userData,
4056 "Element %s is empty\n", node->name);
4057 ctxt->nbErrors++;
4058 } else {
4059 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4060 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004061 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004062 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004063 if (def == NULL)
4064 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004065 def->type = XML_RELAXNG_CHOICE;
4066 if (node->children == NULL) {
4067 if (ctxt->error != NULL)
4068 ctxt->error(ctxt->userData,
4069 "Element %s is empty\n", node->name);
4070 ctxt->nbErrors++;
4071 } else {
4072 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4073 }
4074 } else if (IS_RELAXNG(node, "group")) {
4075 def = xmlRelaxNGNewDefine(ctxt, node);
4076 if (def == NULL)
4077 return(NULL);
4078 def->type = XML_RELAXNG_GROUP;
4079 if (node->children == NULL) {
4080 if (ctxt->error != NULL)
4081 ctxt->error(ctxt->userData,
4082 "Element %s is empty\n", node->name);
4083 ctxt->nbErrors++;
4084 } else {
4085 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4086 }
4087 } else if (IS_RELAXNG(node, "ref")) {
4088 def = xmlRelaxNGNewDefine(ctxt, node);
4089 if (def == NULL)
4090 return(NULL);
4091 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004092 def->name = xmlGetProp(node, BAD_CAST "name");
4093 if (def->name == NULL) {
4094 if (ctxt->error != NULL)
4095 ctxt->error(ctxt->userData,
4096 "ref has no name\n");
4097 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004098 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004099 xmlRelaxNGNormExtSpace(def->name);
4100 if (xmlValidateNCName(def->name, 0)) {
4101 if (ctxt->error != NULL)
4102 ctxt->error(ctxt->userData,
4103 "ref name '%s' is not an NCName\n",
4104 def->name);
4105 ctxt->nbErrors++;
4106 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004107 }
4108 if (node->children != NULL) {
4109 if (ctxt->error != NULL)
4110 ctxt->error(ctxt->userData,
4111 "ref is not empty\n");
4112 ctxt->nbErrors++;
4113 }
4114 if (ctxt->grammar->refs == NULL)
4115 ctxt->grammar->refs = xmlHashCreate(10);
4116 if (ctxt->grammar->refs == NULL) {
4117 if (ctxt->error != NULL)
4118 ctxt->error(ctxt->userData,
4119 "Could not create references hash\n");
4120 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004121 def = NULL;
4122 } else {
4123 int tmp;
4124
4125 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4126 if (tmp < 0) {
4127 xmlRelaxNGDefinePtr prev;
4128
4129 prev = (xmlRelaxNGDefinePtr)
4130 xmlHashLookup(ctxt->grammar->refs, def->name);
4131 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004132 if (def->name != NULL) {
4133 if (ctxt->error != NULL)
4134 ctxt->error(ctxt->userData,
4135 "Error refs definitions '%s'\n",
4136 def->name);
4137 } else {
4138 if (ctxt->error != NULL)
4139 ctxt->error(ctxt->userData,
4140 "Error refs definitions\n");
4141 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004142 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004143 def = NULL;
4144 } else {
4145 def->nextHash = prev->nextHash;
4146 prev->nextHash = def;
4147 }
4148 }
4149 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004150 } else if (IS_RELAXNG(node, "data")) {
4151 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004152 } else if (IS_RELAXNG(node, "value")) {
4153 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004154 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004155 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004156 if (def == NULL)
4157 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004158 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004159 if (node->children == NULL) {
4160 if (ctxt->error != NULL)
4161 ctxt->error(ctxt->userData,
4162 "Element %s is empty\n", node->name);
4163 ctxt->nbErrors++;
4164 } else {
4165 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4166 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004167 } else if (IS_RELAXNG(node, "interleave")) {
4168 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004169 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004170 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004171 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004172 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004173 if (def == NULL)
4174 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004175 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004176 if (node->children != NULL) {
4177 if (ctxt->error != NULL)
4178 ctxt->error(ctxt->userData,
4179 "xmlRelaxNGParse: notAllowed element is not empty\n");
4180 ctxt->nbErrors++;
4181 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004182 } else if (IS_RELAXNG(node, "grammar")) {
4183 xmlRelaxNGGrammarPtr grammar, old;
4184 xmlRelaxNGGrammarPtr oldparent;
4185
Daniel Veillardc482e262003-02-26 14:48:48 +00004186#ifdef DEBUG_GRAMMAR
4187 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4188#endif
4189
Daniel Veillard419a7682003-02-03 23:22:49 +00004190 oldparent = ctxt->parentgrammar;
4191 old = ctxt->grammar;
4192 ctxt->parentgrammar = old;
4193 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4194 if (old != NULL) {
4195 ctxt->grammar = old;
4196 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004197#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004198 if (grammar != NULL) {
4199 grammar->next = old->next;
4200 old->next = grammar;
4201 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004202#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004203 }
4204 if (grammar != NULL)
4205 def = grammar->start;
4206 else
4207 def = NULL;
4208 } else if (IS_RELAXNG(node, "parentRef")) {
4209 if (ctxt->parentgrammar == NULL) {
4210 if (ctxt->error != NULL)
4211 ctxt->error(ctxt->userData,
4212 "Use of parentRef without a parent grammar\n");
4213 ctxt->nbErrors++;
4214 return(NULL);
4215 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004216 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004217 if (def == NULL)
4218 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004219 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004220 def->name = xmlGetProp(node, BAD_CAST "name");
4221 if (def->name == NULL) {
4222 if (ctxt->error != NULL)
4223 ctxt->error(ctxt->userData,
4224 "parentRef has no name\n");
4225 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004226 } else {
4227 xmlRelaxNGNormExtSpace(def->name);
4228 if (xmlValidateNCName(def->name, 0)) {
4229 if (ctxt->error != NULL)
4230 ctxt->error(ctxt->userData,
4231 "parentRef name '%s' is not an NCName\n",
4232 def->name);
4233 ctxt->nbErrors++;
4234 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004235 }
4236 if (node->children != NULL) {
4237 if (ctxt->error != NULL)
4238 ctxt->error(ctxt->userData,
4239 "parentRef is not empty\n");
4240 ctxt->nbErrors++;
4241 }
4242 if (ctxt->parentgrammar->refs == NULL)
4243 ctxt->parentgrammar->refs = xmlHashCreate(10);
4244 if (ctxt->parentgrammar->refs == NULL) {
4245 if (ctxt->error != NULL)
4246 ctxt->error(ctxt->userData,
4247 "Could not create references hash\n");
4248 ctxt->nbErrors++;
4249 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004250 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004251 int tmp;
4252
4253 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4254 if (tmp < 0) {
4255 xmlRelaxNGDefinePtr prev;
4256
4257 prev = (xmlRelaxNGDefinePtr)
4258 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4259 if (prev == NULL) {
4260 if (ctxt->error != NULL)
4261 ctxt->error(ctxt->userData,
4262 "Internal error parentRef definitions '%s'\n",
4263 def->name);
4264 ctxt->nbErrors++;
4265 def = NULL;
4266 } else {
4267 def->nextHash = prev->nextHash;
4268 prev->nextHash = def;
4269 }
4270 }
4271 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004272 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004273 if (node->children == NULL) {
4274 if (ctxt->error != NULL)
4275 ctxt->error(ctxt->userData,
4276 "Mixed is empty\n");
4277 ctxt->nbErrors++;
4278 def = NULL;
4279 } else {
4280 def = xmlRelaxNGParseInterleave(ctxt, node);
4281 if (def != NULL) {
4282 xmlRelaxNGDefinePtr tmp;
4283
4284 if ((def->content != NULL) && (def->content->next != NULL)) {
4285 tmp = xmlRelaxNGNewDefine(ctxt, node);
4286 if (tmp != NULL) {
4287 tmp->type = XML_RELAXNG_GROUP;
4288 tmp->content = def->content;
4289 def->content = tmp;
4290 }
4291 }
4292
4293 tmp = xmlRelaxNGNewDefine(ctxt, node);
4294 if (tmp == NULL)
4295 return(def);
4296 tmp->type = XML_RELAXNG_TEXT;
4297 tmp->next = def->content;
4298 def->content = tmp;
4299 }
4300 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004301 } else {
4302 if (ctxt->error != NULL)
4303 ctxt->error(ctxt->userData,
4304 "Unexpected node %s is not a pattern\n",
4305 node->name);
4306 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004307 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004308 }
4309 return(def);
4310}
4311
4312/**
4313 * xmlRelaxNGParseAttribute:
4314 * @ctxt: a Relax-NG parser context
4315 * @node: the element node
4316 *
4317 * parse the content of a RelaxNG attribute node.
4318 *
4319 * Returns the definition pointer or NULL in case of error.
4320 */
4321static xmlRelaxNGDefinePtr
4322xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004323 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004324 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004325 int old_flags;
4326
Daniel Veillardfd573f12003-03-16 17:52:32 +00004327 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004328 if (ret == NULL)
4329 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004330 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004331 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004332 child = node->children;
4333 if (child == NULL) {
4334 if (ctxt->error != NULL)
4335 ctxt->error(ctxt->userData,
4336 "xmlRelaxNGParseattribute: attribute has no children\n");
4337 ctxt->nbErrors++;
4338 return(ret);
4339 }
4340 old_flags = ctxt->flags;
4341 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004342 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4343 if (cur != NULL)
4344 child = child->next;
4345
Daniel Veillardd2298792003-02-14 16:54:11 +00004346 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004347 cur = xmlRelaxNGParsePattern(ctxt, child);
4348 if (cur != NULL) {
4349 switch (cur->type) {
4350 case XML_RELAXNG_EMPTY:
4351 case XML_RELAXNG_NOT_ALLOWED:
4352 case XML_RELAXNG_TEXT:
4353 case XML_RELAXNG_ELEMENT:
4354 case XML_RELAXNG_DATATYPE:
4355 case XML_RELAXNG_VALUE:
4356 case XML_RELAXNG_LIST:
4357 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004358 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004359 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004360 case XML_RELAXNG_DEF:
4361 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004362 case XML_RELAXNG_ZEROORMORE:
4363 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004364 case XML_RELAXNG_CHOICE:
4365 case XML_RELAXNG_GROUP:
4366 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004367 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004368 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004369 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004370 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004371 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004372 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004373 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004374 if (ctxt->error != NULL)
4375 ctxt->error(ctxt->userData,
4376 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004377 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004378 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004379 case XML_RELAXNG_NOOP:
4380 TODO
4381 if (ctxt->error != NULL)
4382 ctxt->error(ctxt->userData,
4383 "Internal error, noop found\n");
4384 ctxt->nbErrors++;
4385 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004386 }
4387 }
4388 child = child->next;
4389 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004390 if (child != NULL) {
4391 if (ctxt->error != NULL)
4392 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4393 ctxt->nbErrors++;
4394 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004395 ctxt->flags = old_flags;
4396 return(ret);
4397}
4398
4399/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004400 * xmlRelaxNGParseExceptNameClass:
4401 * @ctxt: a Relax-NG parser context
4402 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004403 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004404 *
4405 * parse the content of a RelaxNG nameClass node.
4406 *
4407 * Returns the definition pointer or NULL in case of error.
4408 */
4409static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004410xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4411 xmlNodePtr node, int attr) {
4412 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4413 xmlNodePtr child;
4414
Daniel Veillardd2298792003-02-14 16:54:11 +00004415 if (!IS_RELAXNG(node, "except")) {
4416 if (ctxt->error != NULL)
4417 ctxt->error(ctxt->userData,
4418 "Expecting an except node\n");
4419 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004420 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004421 }
4422 if (node->next != NULL) {
4423 if (ctxt->error != NULL)
4424 ctxt->error(ctxt->userData,
4425 "exceptNameClass allows only a single except node\n");
4426 ctxt->nbErrors++;
4427 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004428 if (node->children == NULL) {
4429 if (ctxt->error != NULL)
4430 ctxt->error(ctxt->userData,
4431 "except has no content\n");
4432 ctxt->nbErrors++;
4433 return(NULL);
4434 }
4435
Daniel Veillardfd573f12003-03-16 17:52:32 +00004436 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004437 if (ret == NULL)
4438 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004439 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004440 child = node->children;
4441 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004442 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004443 if (cur == NULL)
4444 break;
4445 if (attr)
4446 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004447 else
4448 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004449
Daniel Veillard419a7682003-02-03 23:22:49 +00004450 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004451 if (last == NULL) {
4452 ret->content = cur;
4453 } else {
4454 last->next = cur;
4455 }
4456 last = cur;
4457 }
4458 child = child->next;
4459 }
4460
4461 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004462}
4463
4464/**
4465 * xmlRelaxNGParseNameClass:
4466 * @ctxt: a Relax-NG parser context
4467 * @node: the nameClass node
4468 * @def: the current definition
4469 *
4470 * parse the content of a RelaxNG nameClass node.
4471 *
4472 * Returns the definition pointer or NULL in case of error.
4473 */
4474static xmlRelaxNGDefinePtr
4475xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4476 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004477 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004478 xmlChar *val;
4479
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004480 ret = def;
4481 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4482 (IS_RELAXNG(node, "nsName"))) {
4483 if ((def->type != XML_RELAXNG_ELEMENT) &&
4484 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004485 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004486 if (ret == NULL)
4487 return(NULL);
4488 ret->parent = def;
4489 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4490 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004491 else
4492 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004493 }
4494 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004495 if (IS_RELAXNG(node, "name")) {
4496 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004497 xmlRelaxNGNormExtSpace(val);
4498 if (xmlValidateNCName(val, 0)) {
4499 if (ctxt->error != NULL) {
4500 if (node->parent != NULL)
4501 ctxt->error(ctxt->userData,
4502 "Element %s name '%s' is not an NCName\n",
4503 node->parent->name, val);
4504 else
4505 ctxt->error(ctxt->userData,
4506 "name '%s' is not an NCName\n",
4507 val);
4508 }
4509 ctxt->nbErrors++;
4510 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004511 ret->name = val;
4512 val = xmlGetProp(node, BAD_CAST "ns");
4513 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004514 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4515 (val != NULL) &&
4516 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4517 ctxt->error(ctxt->userData,
4518 "Attribute with namespace '%s' is not allowed\n",
4519 val);
4520 ctxt->nbErrors++;
4521 }
4522 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4523 (val != NULL) &&
4524 (val[0] == 0) &&
4525 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4526 ctxt->error(ctxt->userData,
4527 "Attribute with QName 'xmlns' is not allowed\n",
4528 val);
4529 ctxt->nbErrors++;
4530 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004531 } else if (IS_RELAXNG(node, "anyName")) {
4532 ret->name = NULL;
4533 ret->ns = NULL;
4534 if (node->children != NULL) {
4535 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004536 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4537 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004538 }
4539 } else if (IS_RELAXNG(node, "nsName")) {
4540 ret->name = NULL;
4541 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4542 if (ret->ns == NULL) {
4543 if (ctxt->error != NULL)
4544 ctxt->error(ctxt->userData,
4545 "nsName has no ns attribute\n");
4546 ctxt->nbErrors++;
4547 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004548 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4549 (ret->ns != NULL) &&
4550 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4551 ctxt->error(ctxt->userData,
4552 "Attribute with namespace '%s' is not allowed\n",
4553 ret->ns);
4554 ctxt->nbErrors++;
4555 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004556 if (node->children != NULL) {
4557 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004558 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4559 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004560 }
4561 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004562 xmlNodePtr child;
4563 xmlRelaxNGDefinePtr last = NULL;
4564
4565 ret = xmlRelaxNGNewDefine(ctxt, node);
4566 if (ret == NULL)
4567 return(NULL);
4568 ret->parent = def;
4569 ret->type = XML_RELAXNG_CHOICE;
4570
Daniel Veillardd2298792003-02-14 16:54:11 +00004571 if (node->children == NULL) {
4572 if (ctxt->error != NULL)
4573 ctxt->error(ctxt->userData,
4574 "Element choice is empty\n");
4575 ctxt->nbErrors++;
4576 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004577
4578 child = node->children;
4579 while (child != NULL) {
4580 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4581 if (tmp != NULL) {
4582 if (last == NULL) {
4583 last = ret->nameClass = tmp;
4584 } else {
4585 last->next = tmp;
4586 last = tmp;
4587 }
4588 }
4589 child = child->next;
4590 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004591 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004592 } else {
4593 if (ctxt->error != NULL)
4594 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004595 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004596 node->name);
4597 ctxt->nbErrors++;
4598 return(NULL);
4599 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004600 if (ret != def) {
4601 if (def->nameClass == NULL) {
4602 def->nameClass = ret;
4603 } else {
4604 tmp = def->nameClass;
4605 while (tmp->next != NULL) {
4606 tmp = tmp->next;
4607 }
4608 tmp->next = ret;
4609 }
4610 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004611 return(ret);
4612}
4613
4614/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004615 * xmlRelaxNGParseElement:
4616 * @ctxt: a Relax-NG parser context
4617 * @node: the element node
4618 *
4619 * parse the content of a RelaxNG element node.
4620 *
4621 * Returns the definition pointer or NULL in case of error.
4622 */
4623static xmlRelaxNGDefinePtr
4624xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4625 xmlRelaxNGDefinePtr ret, cur, last;
4626 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004627 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004628
Daniel Veillardfd573f12003-03-16 17:52:32 +00004629 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004630 if (ret == NULL)
4631 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004632 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004633 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004634 child = node->children;
4635 if (child == NULL) {
4636 if (ctxt->error != NULL)
4637 ctxt->error(ctxt->userData,
4638 "xmlRelaxNGParseElement: element has no children\n");
4639 ctxt->nbErrors++;
4640 return(ret);
4641 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004642 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4643 if (cur != NULL)
4644 child = child->next;
4645
Daniel Veillard6eadf632003-01-23 18:29:16 +00004646 if (child == NULL) {
4647 if (ctxt->error != NULL)
4648 ctxt->error(ctxt->userData,
4649 "xmlRelaxNGParseElement: element has no content\n");
4650 ctxt->nbErrors++;
4651 return(ret);
4652 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004653 olddefine = ctxt->define;
4654 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004655 last = NULL;
4656 while (child != NULL) {
4657 cur = xmlRelaxNGParsePattern(ctxt, child);
4658 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004659 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004660 switch (cur->type) {
4661 case XML_RELAXNG_EMPTY:
4662 case XML_RELAXNG_NOT_ALLOWED:
4663 case XML_RELAXNG_TEXT:
4664 case XML_RELAXNG_ELEMENT:
4665 case XML_RELAXNG_DATATYPE:
4666 case XML_RELAXNG_VALUE:
4667 case XML_RELAXNG_LIST:
4668 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004669 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004670 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004671 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004672 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004673 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004674 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004675 case XML_RELAXNG_CHOICE:
4676 case XML_RELAXNG_GROUP:
4677 case XML_RELAXNG_INTERLEAVE:
4678 if (last == NULL) {
4679 ret->content = last = cur;
4680 } else {
4681 if ((last->type == XML_RELAXNG_ELEMENT) &&
4682 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004683 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004684 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004685 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004686 ret->content->content = last;
4687 } else {
4688 ret->content = last;
4689 }
4690 }
4691 last->next = cur;
4692 last = cur;
4693 }
4694 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004695 case XML_RELAXNG_ATTRIBUTE:
4696 cur->next = ret->attrs;
4697 ret->attrs = cur;
4698 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004699 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004700 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004701 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004702 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004703 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004704 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004705 case XML_RELAXNG_NOOP:
4706 TODO
4707 if (ctxt->error != NULL)
4708 ctxt->error(ctxt->userData,
4709 "Internal error, noop found\n");
4710 ctxt->nbErrors++;
4711 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004712 }
4713 }
4714 child = child->next;
4715 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004716 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004717 return(ret);
4718}
4719
4720/**
4721 * xmlRelaxNGParsePatterns:
4722 * @ctxt: a Relax-NG parser context
4723 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004724 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004725 *
4726 * parse the content of a RelaxNG start node.
4727 *
4728 * Returns the definition pointer or NULL in case of error.
4729 */
4730static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004731xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4732 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004733 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004734
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004735 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004736 while (nodes != NULL) {
4737 if (IS_RELAXNG(nodes, "element")) {
4738 cur = xmlRelaxNGParseElement(ctxt, nodes);
4739 if (def == NULL) {
4740 def = last = cur;
4741 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004742 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4743 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004744 def = xmlRelaxNGNewDefine(ctxt, nodes);
4745 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004746 def->content = last;
4747 }
4748 last->next = cur;
4749 last = cur;
4750 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004751 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004752 } else {
4753 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004754 if (cur != NULL) {
4755 if (def == NULL) {
4756 def = last = cur;
4757 } else {
4758 last->next = cur;
4759 last = cur;
4760 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004761 }
4762 }
4763 nodes = nodes->next;
4764 }
4765 return(def);
4766}
4767
4768/**
4769 * xmlRelaxNGParseStart:
4770 * @ctxt: a Relax-NG parser context
4771 * @nodes: start children nodes
4772 *
4773 * parse the content of a RelaxNG start node.
4774 *
4775 * Returns 0 in case of success, -1 in case of error
4776 */
4777static int
4778xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4779 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004780 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004781
Daniel Veillardd2298792003-02-14 16:54:11 +00004782 if (nodes == NULL) {
4783 if (ctxt->error != NULL)
4784 ctxt->error(ctxt->userData,
4785 "start has no children\n");
4786 ctxt->nbErrors++;
4787 return(-1);
4788 }
4789 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004790 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004791 if (def == NULL)
4792 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004793 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004794 if (nodes->children != NULL) {
4795 if (ctxt->error != NULL)
4796 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004797 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004798 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004799 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004800 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004801 if (def == NULL)
4802 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004803 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004804 if (nodes->children != NULL) {
4805 if (ctxt->error != NULL)
4806 ctxt->error(ctxt->userData,
4807 "element notAllowed is not empty\n");
4808 ctxt->nbErrors++;
4809 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004810 } else {
4811 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004812 }
4813 if (ctxt->grammar->start != NULL) {
4814 last = ctxt->grammar->start;
4815 while (last->next != NULL)
4816 last = last->next;
4817 last->next = def;
4818 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004819 ctxt->grammar->start = def;
4820 }
4821 nodes = nodes->next;
4822 if (nodes != NULL) {
4823 if (ctxt->error != NULL)
4824 ctxt->error(ctxt->userData,
4825 "start more than one children\n");
4826 ctxt->nbErrors++;
4827 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004828 }
4829 return(ret);
4830}
4831
4832/**
4833 * xmlRelaxNGParseGrammarContent:
4834 * @ctxt: a Relax-NG parser context
4835 * @nodes: grammar children nodes
4836 *
4837 * parse the content of a RelaxNG grammar node.
4838 *
4839 * Returns 0 in case of success, -1 in case of error
4840 */
4841static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004842xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004843{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004844 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004845
4846 if (nodes == NULL) {
4847 if (ctxt->error != NULL)
4848 ctxt->error(ctxt->userData,
4849 "grammar has no children\n");
4850 ctxt->nbErrors++;
4851 return(-1);
4852 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004853 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004854 if (IS_RELAXNG(nodes, "start")) {
4855 if (nodes->children == NULL) {
4856 if (ctxt->error != NULL)
4857 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004858 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004859 ctxt->nbErrors++;
4860 } else {
4861 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4862 if (tmp != 0)
4863 ret = -1;
4864 }
4865 } else if (IS_RELAXNG(nodes, "define")) {
4866 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4867 if (tmp != 0)
4868 ret = -1;
4869 } else if (IS_RELAXNG(nodes, "include")) {
4870 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4871 if (tmp != 0)
4872 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004873 } else {
4874 if (ctxt->error != NULL)
4875 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004876 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004877 ctxt->nbErrors++;
4878 ret = -1;
4879 }
4880 nodes = nodes->next;
4881 }
4882 return (ret);
4883}
4884
4885/**
4886 * xmlRelaxNGCheckReference:
4887 * @ref: the ref
4888 * @ctxt: a Relax-NG parser context
4889 * @name: the name associated to the defines
4890 *
4891 * Applies the 4.17. combine attribute rule for all the define
4892 * element of a given grammar using the same name.
4893 */
4894static void
4895xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4896 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4897 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004898 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004899
4900 grammar = ctxt->grammar;
4901 if (grammar == NULL) {
4902 if (ctxt->error != NULL)
4903 ctxt->error(ctxt->userData,
4904 "Internal error: no grammar in CheckReference %s\n",
4905 name);
4906 ctxt->nbErrors++;
4907 return;
4908 }
4909 if (ref->content != NULL) {
4910 if (ctxt->error != NULL)
4911 ctxt->error(ctxt->userData,
4912 "Internal error: reference has content in CheckReference %s\n",
4913 name);
4914 ctxt->nbErrors++;
4915 return;
4916 }
4917 if (grammar->defs != NULL) {
4918 def = xmlHashLookup(grammar->defs, name);
4919 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004920 cur = ref;
4921 while (cur != NULL) {
4922 cur->content = def;
4923 cur = cur->nextHash;
4924 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004925 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004926 if (ctxt->error != NULL)
4927 ctxt->error(ctxt->userData,
4928 "Reference %s has no matching definition\n",
4929 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004930 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004931 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004932 } else {
4933 if (ctxt->error != NULL)
4934 ctxt->error(ctxt->userData,
4935 "Reference %s has no matching definition\n",
4936 name);
4937 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004938 }
4939 /*
4940 * TODO: make a closure and verify there is no loop !
4941 */
4942}
4943
4944/**
4945 * xmlRelaxNGCheckCombine:
4946 * @define: the define(s) list
4947 * @ctxt: a Relax-NG parser context
4948 * @name: the name associated to the defines
4949 *
4950 * Applies the 4.17. combine attribute rule for all the define
4951 * element of a given grammar using the same name.
4952 */
4953static void
4954xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4955 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4956 xmlChar *combine;
4957 int choiceOrInterleave = -1;
4958 int missing = 0;
4959 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4960
4961 if (define->nextHash == NULL)
4962 return;
4963 cur = define;
4964 while (cur != NULL) {
4965 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4966 if (combine != NULL) {
4967 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4968 if (choiceOrInterleave == -1)
4969 choiceOrInterleave = 1;
4970 else if (choiceOrInterleave == 0) {
4971 if (ctxt->error != NULL)
4972 ctxt->error(ctxt->userData,
4973 "Defines for %s use both 'choice' and 'interleave'\n",
4974 name);
4975 ctxt->nbErrors++;
4976 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004977 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004978 if (choiceOrInterleave == -1)
4979 choiceOrInterleave = 0;
4980 else if (choiceOrInterleave == 1) {
4981 if (ctxt->error != NULL)
4982 ctxt->error(ctxt->userData,
4983 "Defines for %s use both 'choice' and 'interleave'\n",
4984 name);
4985 ctxt->nbErrors++;
4986 }
4987 } else {
4988 if (ctxt->error != NULL)
4989 ctxt->error(ctxt->userData,
4990 "Defines for %s use unknown combine value '%s''\n",
4991 name, combine);
4992 ctxt->nbErrors++;
4993 }
4994 xmlFree(combine);
4995 } else {
4996 if (missing == 0)
4997 missing = 1;
4998 else {
4999 if (ctxt->error != NULL)
5000 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005001 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005002 name);
5003 ctxt->nbErrors++;
5004 }
5005 }
5006
5007 cur = cur->nextHash;
5008 }
5009#ifdef DEBUG
5010 xmlGenericError(xmlGenericErrorContext,
5011 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5012 name, choiceOrInterleave);
5013#endif
5014 if (choiceOrInterleave == -1)
5015 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005016 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005017 if (cur == NULL)
5018 return;
5019 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005020 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005021 else
5022 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005023 tmp = define;
5024 last = NULL;
5025 while (tmp != NULL) {
5026 if (tmp->content != NULL) {
5027 if (tmp->content->next != NULL) {
5028 /*
5029 * we need first to create a wrapper.
5030 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005031 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005032 if (tmp2 == NULL)
5033 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005034 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005035 tmp2->content = tmp->content;
5036 } else {
5037 tmp2 = tmp->content;
5038 }
5039 if (last == NULL) {
5040 cur->content = tmp2;
5041 } else {
5042 last->next = tmp2;
5043 }
5044 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005045 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005046 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005047 tmp = tmp->nextHash;
5048 }
5049 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005050 if (choiceOrInterleave == 0) {
5051 if (ctxt->interleaves == NULL)
5052 ctxt->interleaves = xmlHashCreate(10);
5053 if (ctxt->interleaves == NULL) {
5054 if (ctxt->error != NULL)
5055 ctxt->error(ctxt->userData,
5056 "Failed to create interleaves hash table\n");
5057 ctxt->nbErrors++;
5058 } else {
5059 char tmpname[32];
5060
5061 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5062 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5063 if (ctxt->error != NULL)
5064 ctxt->error(ctxt->userData,
5065 "Failed to add %s to hash table\n", tmpname);
5066 ctxt->nbErrors++;
5067 }
5068 }
5069 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005070}
5071
5072/**
5073 * xmlRelaxNGCombineStart:
5074 * @ctxt: a Relax-NG parser context
5075 * @grammar: the grammar
5076 *
5077 * Applies the 4.17. combine rule for all the start
5078 * element of a given grammar.
5079 */
5080static void
5081xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5082 xmlRelaxNGGrammarPtr grammar) {
5083 xmlRelaxNGDefinePtr starts;
5084 xmlChar *combine;
5085 int choiceOrInterleave = -1;
5086 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005087 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005088
Daniel Veillard2df2de22003-02-17 23:34:33 +00005089 starts = grammar->start;
5090 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005091 return;
5092 cur = starts;
5093 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005094 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5095 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5096 combine = NULL;
5097 if (ctxt->error != NULL)
5098 ctxt->error(ctxt->userData,
5099 "Internal error: start element not found\n");
5100 ctxt->nbErrors++;
5101 } else {
5102 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5103 }
5104
Daniel Veillard6eadf632003-01-23 18:29:16 +00005105 if (combine != NULL) {
5106 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5107 if (choiceOrInterleave == -1)
5108 choiceOrInterleave = 1;
5109 else if (choiceOrInterleave == 0) {
5110 if (ctxt->error != NULL)
5111 ctxt->error(ctxt->userData,
5112 "<start> use both 'choice' and 'interleave'\n");
5113 ctxt->nbErrors++;
5114 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005115 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005116 if (choiceOrInterleave == -1)
5117 choiceOrInterleave = 0;
5118 else if (choiceOrInterleave == 1) {
5119 if (ctxt->error != NULL)
5120 ctxt->error(ctxt->userData,
5121 "<start> use both 'choice' and 'interleave'\n");
5122 ctxt->nbErrors++;
5123 }
5124 } else {
5125 if (ctxt->error != NULL)
5126 ctxt->error(ctxt->userData,
5127 "<start> uses unknown combine value '%s''\n", combine);
5128 ctxt->nbErrors++;
5129 }
5130 xmlFree(combine);
5131 } else {
5132 if (missing == 0)
5133 missing = 1;
5134 else {
5135 if (ctxt->error != NULL)
5136 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005137 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005138 ctxt->nbErrors++;
5139 }
5140 }
5141
Daniel Veillard2df2de22003-02-17 23:34:33 +00005142 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005143 }
5144#ifdef DEBUG
5145 xmlGenericError(xmlGenericErrorContext,
5146 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5147 choiceOrInterleave);
5148#endif
5149 if (choiceOrInterleave == -1)
5150 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005151 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005152 if (cur == NULL)
5153 return;
5154 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005155 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005156 else
5157 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005158 cur->content = grammar->start;
5159 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005160 if (choiceOrInterleave == 0) {
5161 if (ctxt->interleaves == NULL)
5162 ctxt->interleaves = xmlHashCreate(10);
5163 if (ctxt->interleaves == NULL) {
5164 if (ctxt->error != NULL)
5165 ctxt->error(ctxt->userData,
5166 "Failed to create interleaves hash table\n");
5167 ctxt->nbErrors++;
5168 } else {
5169 char tmpname[32];
5170
5171 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5172 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5173 if (ctxt->error != NULL)
5174 ctxt->error(ctxt->userData,
5175 "Failed to add %s to hash table\n", tmpname);
5176 ctxt->nbErrors++;
5177 }
5178 }
5179 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005180}
5181
5182/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005183 * xmlRelaxNGCheckCycles:
5184 * @ctxt: a Relax-NG parser context
5185 * @nodes: grammar children nodes
5186 * @depth: the counter
5187 *
5188 * Check for cycles.
5189 *
5190 * Returns 0 if check passed, and -1 in case of error
5191 */
5192static int
5193xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5194 xmlRelaxNGDefinePtr cur, int depth) {
5195 int ret = 0;
5196
5197 while ((ret == 0) && (cur != NULL)) {
5198 if ((cur->type == XML_RELAXNG_REF) ||
5199 (cur->type == XML_RELAXNG_PARENTREF)) {
5200 if (cur->depth == -1) {
5201 cur->depth = depth;
5202 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5203 cur->depth = -2;
5204 } else if (depth == cur->depth) {
5205 if (ctxt->error != NULL)
5206 ctxt->error(ctxt->userData,
5207 "Detected a cycle in %s references\n", cur->name);
5208 ctxt->nbErrors++;
5209 return(-1);
5210 }
5211 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5212 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5213 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005214 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005215 }
5216 cur = cur->next;
5217 }
5218 return(ret);
5219}
5220
5221/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005222 * xmlRelaxNGTryUnlink:
5223 * @ctxt: a Relax-NG parser context
5224 * @cur: the definition to unlink
5225 * @parent: the parent definition
5226 * @prev: the previous sibling definition
5227 *
5228 * Try to unlink a definition. If not possble make it a NOOP
5229 *
5230 * Returns the new prev definition
5231 */
5232static xmlRelaxNGDefinePtr
5233xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5234 xmlRelaxNGDefinePtr cur,
5235 xmlRelaxNGDefinePtr parent,
5236 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005237 if (prev != NULL) {
5238 prev->next = cur->next;
5239 } else {
5240 if (parent != NULL) {
5241 if (parent->content == cur)
5242 parent->content = cur->next;
5243 else if (parent->attrs == cur)
5244 parent->attrs = cur->next;
5245 else if (parent->nameClass == cur)
5246 parent->nameClass = cur->next;
5247 } else {
5248 cur->type = XML_RELAXNG_NOOP;
5249 prev = cur;
5250 }
5251 }
5252 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005253}
5254
5255/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005256 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005257 * @ctxt: a Relax-NG parser context
5258 * @nodes: grammar children nodes
5259 *
5260 * Check for simplification of empty and notAllowed
5261 */
5262static void
5263xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5264 xmlRelaxNGDefinePtr cur,
5265 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005266 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005267
Daniel Veillardfd573f12003-03-16 17:52:32 +00005268 while (cur != NULL) {
5269 if ((cur->type == XML_RELAXNG_REF) ||
5270 (cur->type == XML_RELAXNG_PARENTREF)) {
5271 if (cur->depth != -3) {
5272 cur->depth = -3;
5273 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005274 }
5275 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005276 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005277 if ((parent != NULL) &&
5278 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5279 (parent->type == XML_RELAXNG_LIST) ||
5280 (parent->type == XML_RELAXNG_GROUP) ||
5281 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005282 (parent->type == XML_RELAXNG_ONEORMORE) ||
5283 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005284 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005285 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005286 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005287 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005288 (parent->type == XML_RELAXNG_CHOICE)) {
5289 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5290 } else
5291 prev = cur;
5292 } else if (cur->type == XML_RELAXNG_EMPTY){
5293 cur->parent = parent;
5294 if ((parent != NULL) &&
5295 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5296 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005297 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005298 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005299 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005300 if ((parent != NULL) &&
5301 ((parent->type == XML_RELAXNG_GROUP) ||
5302 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5303 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5304 } else
5305 prev = cur;
5306 } else {
5307 cur->parent = parent;
5308 if (cur->content != NULL)
5309 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5310 if (cur->attrs != NULL)
5311 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5312 if (cur->nameClass != NULL)
5313 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5314 /*
5315 * This may result in a simplification
5316 */
5317 if ((cur->type == XML_RELAXNG_GROUP) ||
5318 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5319 if (cur->content == NULL)
5320 cur->type = XML_RELAXNG_EMPTY;
5321 else if (cur->content->next == NULL) {
5322 if ((parent == NULL) && (prev == NULL)) {
5323 cur->type = XML_RELAXNG_NOOP;
5324 } else if (prev == NULL) {
5325 parent->content = cur->content;
5326 cur->content->next = cur->next;
5327 cur = cur->content;
5328 } else {
5329 cur->content->next = cur->next;
5330 prev->next = cur->content;
5331 cur = cur->content;
5332 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005333 }
5334 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005335 /*
5336 * the current node may have been transformed back
5337 */
5338 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5339 (cur->content != NULL) &&
5340 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5341 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5342 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5343 if ((parent != NULL) &&
5344 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5345 (parent->type == XML_RELAXNG_LIST) ||
5346 (parent->type == XML_RELAXNG_GROUP) ||
5347 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5348 (parent->type == XML_RELAXNG_ONEORMORE) ||
5349 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5350 parent->type = XML_RELAXNG_NOT_ALLOWED;
5351 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005352 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005353 if ((parent != NULL) &&
5354 (parent->type == XML_RELAXNG_CHOICE)) {
5355 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5356 } else
5357 prev = cur;
5358 } else if (cur->type == XML_RELAXNG_EMPTY){
5359 if ((parent != NULL) &&
5360 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5361 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5362 parent->type = XML_RELAXNG_EMPTY;
5363 break;
5364 }
5365 if ((parent != NULL) &&
5366 ((parent->type == XML_RELAXNG_GROUP) ||
5367 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5368 (parent->type == XML_RELAXNG_CHOICE))) {
5369 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5370 } else
5371 prev = cur;
5372 } else {
5373 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005374 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005375 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005376 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005377 }
5378}
5379
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005380/**
5381 * xmlRelaxNGGroupContentType:
5382 * @ct1: the first content type
5383 * @ct2: the second content type
5384 *
5385 * Try to group 2 content types
5386 *
5387 * Returns the content type
5388 */
5389static xmlRelaxNGContentType
5390xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5391 xmlRelaxNGContentType ct2) {
5392 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5393 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5394 return(XML_RELAXNG_CONTENT_ERROR);
5395 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5396 return(ct2);
5397 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5398 return(ct1);
5399 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5400 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5401 return(XML_RELAXNG_CONTENT_COMPLEX);
5402 return(XML_RELAXNG_CONTENT_ERROR);
5403}
5404
5405/**
5406 * xmlRelaxNGMaxContentType:
5407 * @ct1: the first content type
5408 * @ct2: the second content type
5409 *
5410 * Compute the max content-type
5411 *
5412 * Returns the content type
5413 */
5414static xmlRelaxNGContentType
5415xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5416 xmlRelaxNGContentType ct2) {
5417 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5418 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5419 return(XML_RELAXNG_CONTENT_ERROR);
5420 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5421 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5422 return(XML_RELAXNG_CONTENT_SIMPLE);
5423 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5424 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5425 return(XML_RELAXNG_CONTENT_COMPLEX);
5426 return(XML_RELAXNG_CONTENT_EMPTY);
5427}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005428
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005429/**
5430 * xmlRelaxNGCheckRules:
5431 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005432 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005433 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005434 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005435 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005436 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005437 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005438 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005439 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005440static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005441xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5442 xmlRelaxNGDefinePtr cur, int flags,
5443 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005444 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005445 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005446
Daniel Veillardfd573f12003-03-16 17:52:32 +00005447 while (cur != NULL) {
5448 ret = XML_RELAXNG_CONTENT_EMPTY;
5449 if ((cur->type == XML_RELAXNG_REF) ||
5450 (cur->type == XML_RELAXNG_PARENTREF)) {
5451 if (flags & XML_RELAXNG_IN_LIST) {
5452 if (ctxt->error != NULL)
5453 ctxt->error(ctxt->userData,
5454 "Found forbidden pattern list//ref\n");
5455 ctxt->nbErrors++;
5456 }
5457 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5458 if (ctxt->error != NULL)
5459 ctxt->error(ctxt->userData,
5460 "Found forbidden pattern data/except//ref\n");
5461 ctxt->nbErrors++;
5462 }
5463 if (cur->depth > -4) {
5464 cur->depth = -4;
5465 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5466 flags, cur->type);
5467 cur->depth = ret - 15 ;
5468 } else if (cur->depth == -4) {
5469 ret = XML_RELAXNG_CONTENT_COMPLEX;
5470 } else {
5471 ret = (xmlRelaxNGContentType) cur->depth + 15;
5472 }
5473 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5474 /*
5475 * The 7.3 Attribute derivation rule for groups is plugged there
5476 */
5477 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5478 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5479 if (ctxt->error != NULL)
5480 ctxt->error(ctxt->userData,
5481 "Found forbidden pattern data/except//element(ref)\n");
5482 ctxt->nbErrors++;
5483 }
5484 if (flags & XML_RELAXNG_IN_LIST) {
5485 if (ctxt->error != NULL)
5486 ctxt->error(ctxt->userData,
5487 "Found forbidden pattern list//element(ref)\n");
5488 ctxt->nbErrors++;
5489 }
5490 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5491 if (ctxt->error != NULL)
5492 ctxt->error(ctxt->userData,
5493 "Found forbidden pattern attribute//element(ref)\n");
5494 ctxt->nbErrors++;
5495 }
5496 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5497 if (ctxt->error != NULL)
5498 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005499 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005500 ctxt->nbErrors++;
5501 }
5502 /*
5503 * reset since in the simple form elements are only child
5504 * of grammar/define
5505 */
5506 nflags = 0;
5507 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5508 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5509 if (ctxt->error != NULL)
5510 ctxt->error(ctxt->userData,
5511 "Element %s attributes have a content type error\n",
5512 cur->name);
5513 ctxt->nbErrors++;
5514 }
5515 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5516 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5517 if (ctxt->error != NULL)
5518 ctxt->error(ctxt->userData,
5519 "Element %s has a content type error\n",
5520 cur->name);
5521 ctxt->nbErrors++;
5522 } else {
5523 ret = XML_RELAXNG_CONTENT_COMPLEX;
5524 }
5525 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5526 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5527 if (ctxt->error != NULL)
5528 ctxt->error(ctxt->userData,
5529 "Found forbidden pattern attribute//attribute\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//attribute\n");
5536 ctxt->nbErrors++;
5537 }
5538 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5539 if (ctxt->error != NULL)
5540 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005541 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005542 ctxt->nbErrors++;
5543 }
5544 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5545 if (ctxt->error != NULL)
5546 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005547 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005548 ctxt->nbErrors++;
5549 }
5550 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5551 if (ctxt->error != NULL)
5552 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005553 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005554 ctxt->nbErrors++;
5555 }
5556 if (flags & XML_RELAXNG_IN_START) {
5557 if (ctxt->error != NULL)
5558 ctxt->error(ctxt->userData,
5559 "Found forbidden pattern start//attribute\n");
5560 ctxt->nbErrors++;
5561 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005562 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5563 if (cur->ns == NULL) {
5564 if (ctxt->error != NULL)
5565 ctxt->error(ctxt->userData,
5566 "Found anyName attribute without oneOrMore ancestor\n");
5567 ctxt->nbErrors++;
5568 } else {
5569 if (ctxt->error != NULL)
5570 ctxt->error(ctxt->userData,
5571 "Found nsName attribute without oneOrMore ancestor\n");
5572 ctxt->nbErrors++;
5573 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005574 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005575 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5576 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5577 ret = XML_RELAXNG_CONTENT_EMPTY;
5578 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5579 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5580 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5581 if (ctxt->error != NULL)
5582 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005583 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005584 ctxt->nbErrors++;
5585 }
5586 if (flags & XML_RELAXNG_IN_START) {
5587 if (ctxt->error != NULL)
5588 ctxt->error(ctxt->userData,
5589 "Found forbidden pattern start//oneOrMore\n");
5590 ctxt->nbErrors++;
5591 }
5592 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5593 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5594 ret = xmlRelaxNGGroupContentType(ret, ret);
5595 } else if (cur->type == XML_RELAXNG_LIST) {
5596 if (flags & XML_RELAXNG_IN_LIST) {
5597 if (ctxt->error != NULL)
5598 ctxt->error(ctxt->userData,
5599 "Found forbidden pattern list//list\n");
5600 ctxt->nbErrors++;
5601 }
5602 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5603 if (ctxt->error != NULL)
5604 ctxt->error(ctxt->userData,
5605 "Found forbidden pattern data/except//list\n");
5606 ctxt->nbErrors++;
5607 }
5608 if (flags & XML_RELAXNG_IN_START) {
5609 if (ctxt->error != NULL)
5610 ctxt->error(ctxt->userData,
5611 "Found forbidden pattern start//list\n");
5612 ctxt->nbErrors++;
5613 }
5614 nflags = flags | XML_RELAXNG_IN_LIST;
5615 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5616 } else if (cur->type == XML_RELAXNG_GROUP) {
5617 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5618 if (ctxt->error != NULL)
5619 ctxt->error(ctxt->userData,
5620 "Found forbidden pattern data/except//group\n");
5621 ctxt->nbErrors++;
5622 }
5623 if (flags & XML_RELAXNG_IN_START) {
5624 if (ctxt->error != NULL)
5625 ctxt->error(ctxt->userData,
5626 "Found forbidden pattern start//group\n");
5627 ctxt->nbErrors++;
5628 }
5629 if (flags & XML_RELAXNG_IN_ONEORMORE)
5630 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5631 else
5632 nflags = flags;
5633 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5634 /*
5635 * The 7.3 Attribute derivation rule for groups is plugged there
5636 */
5637 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5638 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5639 if (flags & XML_RELAXNG_IN_LIST) {
5640 if (ctxt->error != NULL)
5641 ctxt->error(ctxt->userData,
5642 "Found forbidden pattern list//interleave\n");
5643 ctxt->nbErrors++;
5644 }
5645 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5646 if (ctxt->error != NULL)
5647 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005648 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005649 ctxt->nbErrors++;
5650 }
5651 if (flags & XML_RELAXNG_IN_START) {
5652 if (ctxt->error != NULL)
5653 ctxt->error(ctxt->userData,
5654 "Found forbidden pattern start//interleave\n");
5655 ctxt->nbErrors++;
5656 }
5657 if (flags & XML_RELAXNG_IN_ONEORMORE)
5658 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5659 else
5660 nflags = flags;
5661 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5662 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5663 if ((cur->parent != NULL) &&
5664 (cur->parent->type == XML_RELAXNG_DATATYPE))
5665 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5666 else
5667 nflags = flags;
5668 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5669 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5670 if (flags & XML_RELAXNG_IN_START) {
5671 if (ctxt->error != NULL)
5672 ctxt->error(ctxt->userData,
5673 "Found forbidden pattern start//data\n");
5674 ctxt->nbErrors++;
5675 }
5676 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5677 ret = XML_RELAXNG_CONTENT_SIMPLE;
5678 } else if (cur->type == XML_RELAXNG_VALUE) {
5679 if (flags & XML_RELAXNG_IN_START) {
5680 if (ctxt->error != NULL)
5681 ctxt->error(ctxt->userData,
5682 "Found forbidden pattern start//value\n");
5683 ctxt->nbErrors++;
5684 }
5685 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5686 ret = XML_RELAXNG_CONTENT_SIMPLE;
5687 } else if (cur->type == XML_RELAXNG_TEXT) {
5688 if (flags & XML_RELAXNG_IN_LIST) {
5689 if (ctxt->error != NULL)
5690 ctxt->error(ctxt->userData,
5691 "Found forbidden pattern list//text\n");
5692 ctxt->nbErrors++;
5693 }
5694 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5695 if (ctxt->error != NULL)
5696 ctxt->error(ctxt->userData,
5697 "Found forbidden pattern data/except//text\n");
5698 ctxt->nbErrors++;
5699 }
5700 if (flags & XML_RELAXNG_IN_START) {
5701 if (ctxt->error != NULL)
5702 ctxt->error(ctxt->userData,
5703 "Found forbidden pattern start//text\n");
5704 ctxt->nbErrors++;
5705 }
5706 ret = XML_RELAXNG_CONTENT_COMPLEX;
5707 } else if (cur->type == XML_RELAXNG_EMPTY) {
5708 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5709 if (ctxt->error != NULL)
5710 ctxt->error(ctxt->userData,
5711 "Found forbidden pattern data/except//empty\n");
5712 ctxt->nbErrors++;
5713 }
5714 if (flags & XML_RELAXNG_IN_START) {
5715 if (ctxt->error != NULL)
5716 ctxt->error(ctxt->userData,
5717 "Found forbidden pattern start//empty\n");
5718 ctxt->nbErrors++;
5719 }
5720 ret = XML_RELAXNG_CONTENT_EMPTY;
5721 } else if (cur->type == XML_RELAXNG_CHOICE) {
5722 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5723 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5724 } else {
5725 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5726 }
5727 cur = cur->next;
5728 if (ptype == XML_RELAXNG_GROUP) {
5729 val = xmlRelaxNGGroupContentType(val, ret);
5730 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5731 tmp = xmlRelaxNGGroupContentType(val, ret);
5732 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5733 tmp = xmlRelaxNGMaxContentType(val, ret);
5734 } else if (ptype == XML_RELAXNG_CHOICE) {
5735 val = xmlRelaxNGMaxContentType(val, ret);
5736 } else if (ptype == XML_RELAXNG_LIST) {
5737 val = XML_RELAXNG_CONTENT_SIMPLE;
5738 } else if (ptype == XML_RELAXNG_EXCEPT) {
5739 if (ret == XML_RELAXNG_CONTENT_ERROR)
5740 val = XML_RELAXNG_CONTENT_ERROR;
5741 else
5742 val = XML_RELAXNG_CONTENT_SIMPLE;
5743 } else {
5744 val = xmlRelaxNGGroupContentType(val, ret);
5745 }
5746
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005747 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005748 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005749}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005750
5751/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005752 * xmlRelaxNGParseGrammar:
5753 * @ctxt: a Relax-NG parser context
5754 * @nodes: grammar children nodes
5755 *
5756 * parse a Relax-NG <grammar> node
5757 *
5758 * Returns the internal xmlRelaxNGGrammarPtr built or
5759 * NULL in case of error
5760 */
5761static xmlRelaxNGGrammarPtr
5762xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5763 xmlRelaxNGGrammarPtr ret, tmp, old;
5764
Daniel Veillardc482e262003-02-26 14:48:48 +00005765#ifdef DEBUG_GRAMMAR
5766 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5767#endif
5768
Daniel Veillard6eadf632003-01-23 18:29:16 +00005769 ret = xmlRelaxNGNewGrammar(ctxt);
5770 if (ret == NULL)
5771 return(NULL);
5772
5773 /*
5774 * Link the new grammar in the tree
5775 */
5776 ret->parent = ctxt->grammar;
5777 if (ctxt->grammar != NULL) {
5778 tmp = ctxt->grammar->children;
5779 if (tmp == NULL) {
5780 ctxt->grammar->children = ret;
5781 } else {
5782 while (tmp->next != NULL)
5783 tmp = tmp->next;
5784 tmp->next = ret;
5785 }
5786 }
5787
5788 old = ctxt->grammar;
5789 ctxt->grammar = ret;
5790 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5791 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005792 if (ctxt->grammar == NULL) {
5793 if (ctxt->error != NULL)
5794 ctxt->error(ctxt->userData,
5795 "Failed to parse <grammar> content\n");
5796 ctxt->nbErrors++;
5797 } else if (ctxt->grammar->start == NULL) {
5798 if (ctxt->error != NULL)
5799 ctxt->error(ctxt->userData,
5800 "Element <grammar> has no <start>\n");
5801 ctxt->nbErrors++;
5802 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005803
5804 /*
5805 * Apply 4.17 mergingd rules to defines and starts
5806 */
5807 xmlRelaxNGCombineStart(ctxt, ret);
5808 if (ret->defs != NULL) {
5809 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5810 ctxt);
5811 }
5812
5813 /*
5814 * link together defines and refs in this grammar
5815 */
5816 if (ret->refs != NULL) {
5817 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5818 ctxt);
5819 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005820
Daniel Veillard6eadf632003-01-23 18:29:16 +00005821 ctxt->grammar = old;
5822 return(ret);
5823}
5824
5825/**
5826 * xmlRelaxNGParseDocument:
5827 * @ctxt: a Relax-NG parser context
5828 * @node: the root node of the RelaxNG schema
5829 *
5830 * parse a Relax-NG definition resource and build an internal
5831 * xmlRelaxNG struture which can be used to validate instances.
5832 *
5833 * Returns the internal XML RelaxNG structure built or
5834 * NULL in case of error
5835 */
5836static xmlRelaxNGPtr
5837xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5838 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005839 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005840 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005841
5842 if ((ctxt == NULL) || (node == NULL))
5843 return (NULL);
5844
5845 schema = xmlRelaxNGNewRelaxNG(ctxt);
5846 if (schema == NULL)
5847 return(NULL);
5848
Daniel Veillard276be4a2003-01-24 01:03:34 +00005849 olddefine = ctxt->define;
5850 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005851 if (IS_RELAXNG(node, "grammar")) {
5852 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5853 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005854 xmlRelaxNGGrammarPtr tmp, ret;
5855
5856 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005857 if (schema->topgrammar == NULL) {
5858 return(schema);
5859 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005860 /*
5861 * Link the new grammar in the tree
5862 */
5863 ret->parent = ctxt->grammar;
5864 if (ctxt->grammar != NULL) {
5865 tmp = ctxt->grammar->children;
5866 if (tmp == NULL) {
5867 ctxt->grammar->children = ret;
5868 } else {
5869 while (tmp->next != NULL)
5870 tmp = tmp->next;
5871 tmp->next = ret;
5872 }
5873 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005874 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005875 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005876 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005877 if (old != NULL)
5878 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005879 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005880 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005881 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005882 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005883 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005884 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5885 while ((schema->topgrammar->start != NULL) &&
5886 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5887 (schema->topgrammar->start->next != NULL))
5888 schema->topgrammar->start = schema->topgrammar->start->content;
5889 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5890 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005891 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005892 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005893
5894#ifdef DEBUG
5895 if (schema == NULL)
5896 xmlGenericError(xmlGenericErrorContext,
5897 "xmlRelaxNGParseDocument() failed\n");
5898#endif
5899
5900 return (schema);
5901}
5902
5903/************************************************************************
5904 * *
5905 * Reading RelaxNGs *
5906 * *
5907 ************************************************************************/
5908
5909/**
5910 * xmlRelaxNGNewParserCtxt:
5911 * @URL: the location of the schema
5912 *
5913 * Create an XML RelaxNGs parse context for that file/resource expected
5914 * to contain an XML RelaxNGs file.
5915 *
5916 * Returns the parser context or NULL in case of error
5917 */
5918xmlRelaxNGParserCtxtPtr
5919xmlRelaxNGNewParserCtxt(const char *URL) {
5920 xmlRelaxNGParserCtxtPtr ret;
5921
5922 if (URL == NULL)
5923 return(NULL);
5924
5925 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5926 if (ret == NULL) {
5927 xmlGenericError(xmlGenericErrorContext,
5928 "Failed to allocate new schama parser context for %s\n", URL);
5929 return (NULL);
5930 }
5931 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5932 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005933 ret->error = xmlGenericError;
5934 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005935 return (ret);
5936}
5937
5938/**
5939 * xmlRelaxNGNewMemParserCtxt:
5940 * @buffer: a pointer to a char array containing the schemas
5941 * @size: the size of the array
5942 *
5943 * Create an XML RelaxNGs parse context for that memory buffer expected
5944 * to contain an XML RelaxNGs file.
5945 *
5946 * Returns the parser context or NULL in case of error
5947 */
5948xmlRelaxNGParserCtxtPtr
5949xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5950 xmlRelaxNGParserCtxtPtr ret;
5951
5952 if ((buffer == NULL) || (size <= 0))
5953 return(NULL);
5954
5955 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5956 if (ret == NULL) {
5957 xmlGenericError(xmlGenericErrorContext,
5958 "Failed to allocate new schama parser context\n");
5959 return (NULL);
5960 }
5961 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5962 ret->buffer = buffer;
5963 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005964 ret->error = xmlGenericError;
5965 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005966 return (ret);
5967}
5968
5969/**
5970 * xmlRelaxNGFreeParserCtxt:
5971 * @ctxt: the schema parser context
5972 *
5973 * Free the resources associated to the schema parser context
5974 */
5975void
5976xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5977 if (ctxt == NULL)
5978 return;
5979 if (ctxt->URL != NULL)
5980 xmlFree(ctxt->URL);
5981 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005982 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005983 if (ctxt->interleaves != NULL)
5984 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005985 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005986 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005987 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005988 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005989 if (ctxt->docTab != NULL)
5990 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005991 if (ctxt->incTab != NULL)
5992 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005993 if (ctxt->defTab != NULL) {
5994 int i;
5995
5996 for (i = 0;i < ctxt->defNr;i++)
5997 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5998 xmlFree(ctxt->defTab);
5999 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006000 xmlFree(ctxt);
6001}
6002
Daniel Veillard6eadf632003-01-23 18:29:16 +00006003/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006004 * xmlRelaxNGNormExtSpace:
6005 * @value: a value
6006 *
6007 * Removes the leading and ending spaces of the value
6008 * The string is modified "in situ"
6009 */
6010static void
6011xmlRelaxNGNormExtSpace(xmlChar *value) {
6012 xmlChar *start = value;
6013 xmlChar *cur = value;
6014 if (value == NULL)
6015 return;
6016
6017 while (IS_BLANK(*cur)) cur++;
6018 if (cur == start) {
6019 do {
6020 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6021 if (*cur == 0)
6022 return;
6023 start = cur;
6024 while (IS_BLANK(*cur)) cur++;
6025 if (*cur == 0) {
6026 *start = 0;
6027 return;
6028 }
6029 } while (1);
6030 } else {
6031 do {
6032 while ((*cur != 0) && (!IS_BLANK(*cur)))
6033 *start++ = *cur++;
6034 if (*cur == 0) {
6035 *start = 0;
6036 return;
6037 }
6038 /* don't try to normalize the inner spaces */
6039 while (IS_BLANK(*cur)) cur++;
6040 *start++ = *cur++;
6041 if (*cur == 0) {
6042 *start = 0;
6043 return;
6044 }
6045 } while (1);
6046 }
6047}
6048
6049/**
6050 * xmlRelaxNGCheckAttributes:
6051 * @ctxt: a Relax-NG parser context
6052 * @node: a Relax-NG node
6053 *
6054 * Check all the attributes on the given node
6055 */
6056static void
6057xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6058 xmlAttrPtr cur, next;
6059
6060 cur = node->properties;
6061 while (cur != NULL) {
6062 next = cur->next;
6063 if ((cur->ns == NULL) ||
6064 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6065 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6066 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6067 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6068 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6069 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006070 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006071 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6072 if (ctxt->error != NULL)
6073 ctxt->error(ctxt->userData,
6074 "Attribute %s is not allowed on %s\n",
6075 cur->name, node->name);
6076 ctxt->nbErrors++;
6077 }
6078 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6079 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6080 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6081 if (ctxt->error != NULL)
6082 ctxt->error(ctxt->userData,
6083 "Attribute %s is not allowed on %s\n",
6084 cur->name, node->name);
6085 ctxt->nbErrors++;
6086 }
6087 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6088 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6089 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6090 if (ctxt->error != NULL)
6091 ctxt->error(ctxt->userData,
6092 "Attribute %s is not allowed on %s\n",
6093 cur->name, node->name);
6094 ctxt->nbErrors++;
6095 }
6096 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6097 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6098 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6099 if (ctxt->error != NULL)
6100 ctxt->error(ctxt->userData,
6101 "Attribute %s is not allowed on %s\n",
6102 cur->name, node->name);
6103 ctxt->nbErrors++;
6104 }
6105 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6106 xmlChar *val;
6107 xmlURIPtr uri;
6108
6109 val = xmlNodeListGetString(node->doc, cur->children, 1);
6110 if (val != NULL) {
6111 if (val[0] != 0) {
6112 uri = xmlParseURI((const char *) val);
6113 if (uri == NULL) {
6114 if (ctxt->error != NULL)
6115 ctxt->error(ctxt->userData,
6116 "Attribute %s contains invalid URI %s\n",
6117 cur->name, val);
6118 ctxt->nbErrors++;
6119 } else {
6120 if (uri->scheme == NULL) {
6121 if (ctxt->error != NULL)
6122 ctxt->error(ctxt->userData,
6123 "Attribute %s URI %s is not absolute\n",
6124 cur->name, val);
6125 ctxt->nbErrors++;
6126 }
6127 if (uri->fragment != NULL) {
6128 if (ctxt->error != NULL)
6129 ctxt->error(ctxt->userData,
6130 "Attribute %s URI %s has a fragment ID\n",
6131 cur->name, val);
6132 ctxt->nbErrors++;
6133 }
6134 xmlFreeURI(uri);
6135 }
6136 }
6137 xmlFree(val);
6138 }
6139 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6140 if (ctxt->error != NULL)
6141 ctxt->error(ctxt->userData,
6142 "Unknown attribute %s on %s\n",
6143 cur->name, node->name);
6144 ctxt->nbErrors++;
6145 }
6146 }
6147 cur = next;
6148 }
6149}
6150
6151/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006152 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006153 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006154 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006155 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006156 * Cleanup the subtree from unwanted nodes for parsing, resolve
6157 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006158 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006159static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006160xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006161 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006162
Daniel Veillard6eadf632003-01-23 18:29:16 +00006163 delete = NULL;
6164 cur = root;
6165 while (cur != NULL) {
6166 if (delete != NULL) {
6167 xmlUnlinkNode(delete);
6168 xmlFreeNode(delete);
6169 delete = NULL;
6170 }
6171 if (cur->type == XML_ELEMENT_NODE) {
6172 /*
6173 * Simplification 4.1. Annotations
6174 */
6175 if ((cur->ns == NULL) ||
6176 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006177 if ((cur->parent != NULL) &&
6178 (cur->parent->type == XML_ELEMENT_NODE) &&
6179 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6180 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6181 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6182 if (ctxt->error != NULL)
6183 ctxt->error(ctxt->userData,
6184 "element %s doesn't allow foreign elements\n",
6185 cur->parent->name);
6186 ctxt->nbErrors++;
6187 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006188 delete = cur;
6189 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006190 } else {
6191 xmlRelaxNGCleanupAttributes(ctxt, cur);
6192 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6193 xmlChar *href, *ns, *base, *URL;
6194 xmlRelaxNGDocumentPtr docu;
6195 xmlNodePtr tmp;
6196
6197 ns = xmlGetProp(cur, BAD_CAST "ns");
6198 if (ns == NULL) {
6199 tmp = cur->parent;
6200 while ((tmp != NULL) &&
6201 (tmp->type == XML_ELEMENT_NODE)) {
6202 ns = xmlGetProp(tmp, BAD_CAST "ns");
6203 if (ns != NULL)
6204 break;
6205 tmp = tmp->parent;
6206 }
6207 }
6208 href = xmlGetProp(cur, BAD_CAST "href");
6209 if (href == NULL) {
6210 if (ctxt->error != NULL)
6211 ctxt->error(ctxt->userData,
6212 "xmlRelaxNGParse: externalRef has no href attribute\n");
6213 ctxt->nbErrors++;
6214 delete = cur;
6215 goto skip_children;
6216 }
6217 base = xmlNodeGetBase(cur->doc, cur);
6218 URL = xmlBuildURI(href, base);
6219 if (URL == NULL) {
6220 if (ctxt->error != NULL)
6221 ctxt->error(ctxt->userData,
6222 "Failed to compute URL for externalRef %s\n", href);
6223 ctxt->nbErrors++;
6224 if (href != NULL)
6225 xmlFree(href);
6226 if (base != NULL)
6227 xmlFree(base);
6228 delete = cur;
6229 goto skip_children;
6230 }
6231 if (href != NULL)
6232 xmlFree(href);
6233 if (base != NULL)
6234 xmlFree(base);
6235 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6236 if (docu == NULL) {
6237 if (ctxt->error != NULL)
6238 ctxt->error(ctxt->userData,
6239 "Failed to load externalRef %s\n", URL);
6240 ctxt->nbErrors++;
6241 xmlFree(URL);
6242 delete = cur;
6243 goto skip_children;
6244 }
6245 if (ns != NULL)
6246 xmlFree(ns);
6247 xmlFree(URL);
6248 cur->_private = docu;
6249 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6250 xmlChar *href, *ns, *base, *URL;
6251 xmlRelaxNGIncludePtr incl;
6252 xmlNodePtr tmp;
6253
6254 href = xmlGetProp(cur, BAD_CAST "href");
6255 if (href == NULL) {
6256 if (ctxt->error != NULL)
6257 ctxt->error(ctxt->userData,
6258 "xmlRelaxNGParse: include has no href attribute\n");
6259 ctxt->nbErrors++;
6260 delete = cur;
6261 goto skip_children;
6262 }
6263 base = xmlNodeGetBase(cur->doc, cur);
6264 URL = xmlBuildURI(href, base);
6265 if (URL == NULL) {
6266 if (ctxt->error != NULL)
6267 ctxt->error(ctxt->userData,
6268 "Failed to compute URL for include %s\n", href);
6269 ctxt->nbErrors++;
6270 if (href != NULL)
6271 xmlFree(href);
6272 if (base != NULL)
6273 xmlFree(base);
6274 delete = cur;
6275 goto skip_children;
6276 }
6277 if (href != NULL)
6278 xmlFree(href);
6279 if (base != NULL)
6280 xmlFree(base);
6281 ns = xmlGetProp(cur, BAD_CAST "ns");
6282 if (ns == NULL) {
6283 tmp = cur->parent;
6284 while ((tmp != NULL) &&
6285 (tmp->type == XML_ELEMENT_NODE)) {
6286 ns = xmlGetProp(tmp, BAD_CAST "ns");
6287 if (ns != NULL)
6288 break;
6289 tmp = tmp->parent;
6290 }
6291 }
6292 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6293 if (ns != NULL)
6294 xmlFree(ns);
6295 if (incl == NULL) {
6296 if (ctxt->error != NULL)
6297 ctxt->error(ctxt->userData,
6298 "Failed to load include %s\n", URL);
6299 ctxt->nbErrors++;
6300 xmlFree(URL);
6301 delete = cur;
6302 goto skip_children;
6303 }
6304 xmlFree(URL);
6305 cur->_private = incl;
6306 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6307 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6308 xmlChar *name, *ns;
6309 xmlNodePtr text = NULL;
6310
6311 /*
6312 * Simplification 4.8. name attribute of element
6313 * and attribute elements
6314 */
6315 name = xmlGetProp(cur, BAD_CAST "name");
6316 if (name != NULL) {
6317 if (cur->children == NULL) {
6318 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6319 name);
6320 } else {
6321 xmlNodePtr node;
6322 node = xmlNewNode(cur->ns, BAD_CAST "name");
6323 if (node != NULL) {
6324 xmlAddPrevSibling(cur->children, node);
6325 text = xmlNewText(name);
6326 xmlAddChild(node, text);
6327 text = node;
6328 }
6329 }
6330 if (text == NULL) {
6331 if (ctxt->error != NULL)
6332 ctxt->error(ctxt->userData,
6333 "Failed to create a name %s element\n", name);
6334 ctxt->nbErrors++;
6335 }
6336 xmlUnsetProp(cur, BAD_CAST "name");
6337 xmlFree(name);
6338 ns = xmlGetProp(cur, BAD_CAST "ns");
6339 if (ns != NULL) {
6340 if (text != NULL) {
6341 xmlSetProp(text, BAD_CAST "ns", ns);
6342 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6343 }
6344 xmlFree(ns);
6345 } else if (xmlStrEqual(cur->name,
6346 BAD_CAST "attribute")) {
6347 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6348 }
6349 }
6350 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6351 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6352 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6353 /*
6354 * Simplification 4.8. name attribute of element
6355 * and attribute elements
6356 */
6357 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6358 xmlNodePtr node;
6359 xmlChar *ns = NULL;
6360
6361 node = cur->parent;
6362 while ((node != NULL) &&
6363 (node->type == XML_ELEMENT_NODE)) {
6364 ns = xmlGetProp(node, BAD_CAST "ns");
6365 if (ns != NULL) {
6366 break;
6367 }
6368 node = node->parent;
6369 }
6370 if (ns == NULL) {
6371 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6372 } else {
6373 xmlSetProp(cur, BAD_CAST "ns", ns);
6374 xmlFree(ns);
6375 }
6376 }
6377 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6378 xmlChar *name, *local, *prefix;
6379
6380 /*
6381 * Simplification: 4.10. QNames
6382 */
6383 name = xmlNodeGetContent(cur);
6384 if (name != NULL) {
6385 local = xmlSplitQName2(name, &prefix);
6386 if (local != NULL) {
6387 xmlNsPtr ns;
6388
6389 ns = xmlSearchNs(cur->doc, cur, prefix);
6390 if (ns == NULL) {
6391 if (ctxt->error != NULL)
6392 ctxt->error(ctxt->userData,
6393 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6394 ctxt->nbErrors++;
6395 } else {
6396 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6397 xmlNodeSetContent(cur, local);
6398 }
6399 xmlFree(local);
6400 xmlFree(prefix);
6401 }
6402 xmlFree(name);
6403 }
6404 }
6405 /*
6406 * 4.16
6407 */
6408 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6409 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6410 if (ctxt->error != NULL)
6411 ctxt->error(ctxt->userData,
6412 "Found nsName/except//nsName forbidden construct\n");
6413 ctxt->nbErrors++;
6414 }
6415 }
6416 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6417 (cur != root)) {
6418 int oldflags = ctxt->flags;
6419
6420 /*
6421 * 4.16
6422 */
6423 if ((cur->parent != NULL) &&
6424 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6425 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6426 xmlRelaxNGCleanupTree(ctxt, cur);
6427 ctxt->flags = oldflags;
6428 goto skip_children;
6429 } else if ((cur->parent != NULL) &&
6430 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6431 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6432 xmlRelaxNGCleanupTree(ctxt, cur);
6433 ctxt->flags = oldflags;
6434 goto skip_children;
6435 }
6436 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6437 /*
6438 * 4.16
6439 */
6440 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6441 if (ctxt->error != NULL)
6442 ctxt->error(ctxt->userData,
6443 "Found anyName/except//anyName forbidden construct\n");
6444 ctxt->nbErrors++;
6445 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6446 if (ctxt->error != NULL)
6447 ctxt->error(ctxt->userData,
6448 "Found nsName/except//anyName forbidden construct\n");
6449 ctxt->nbErrors++;
6450 }
6451 }
6452 /*
6453 * Thisd is not an else since "include" is transformed
6454 * into a div
6455 */
6456 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6457 xmlChar *ns;
6458 xmlNodePtr child, ins, tmp;
6459
6460 /*
6461 * implements rule 4.11
6462 */
6463
6464 ns = xmlGetProp(cur, BAD_CAST "ns");
6465
6466 child = cur->children;
6467 ins = cur;
6468 while (child != NULL) {
6469 if (ns != NULL) {
6470 if (!xmlHasProp(child, BAD_CAST "ns")) {
6471 xmlSetProp(child, BAD_CAST "ns", ns);
6472 }
6473 }
6474 tmp = child->next;
6475 xmlUnlinkNode(child);
6476 ins = xmlAddNextSibling(ins, child);
6477 child = tmp;
6478 }
6479 if (ns != NULL)
6480 xmlFree(ns);
6481 delete = cur;
6482 goto skip_children;
6483 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006484 }
6485 }
6486 /*
6487 * Simplification 4.2 whitespaces
6488 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006489 else if ((cur->type == XML_TEXT_NODE) ||
6490 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006491 if (IS_BLANK_NODE(cur)) {
6492 if (cur->parent->type == XML_ELEMENT_NODE) {
6493 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6494 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6495 delete = cur;
6496 } else {
6497 delete = cur;
6498 goto skip_children;
6499 }
6500 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006501 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006502 delete = cur;
6503 goto skip_children;
6504 }
6505
6506 /*
6507 * Skip to next node
6508 */
6509 if (cur->children != NULL) {
6510 if ((cur->children->type != XML_ENTITY_DECL) &&
6511 (cur->children->type != XML_ENTITY_REF_NODE) &&
6512 (cur->children->type != XML_ENTITY_NODE)) {
6513 cur = cur->children;
6514 continue;
6515 }
6516 }
6517skip_children:
6518 if (cur->next != NULL) {
6519 cur = cur->next;
6520 continue;
6521 }
6522
6523 do {
6524 cur = cur->parent;
6525 if (cur == NULL)
6526 break;
6527 if (cur == root) {
6528 cur = NULL;
6529 break;
6530 }
6531 if (cur->next != NULL) {
6532 cur = cur->next;
6533 break;
6534 }
6535 } while (cur != NULL);
6536 }
6537 if (delete != NULL) {
6538 xmlUnlinkNode(delete);
6539 xmlFreeNode(delete);
6540 delete = NULL;
6541 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006542}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006543
Daniel Veillardc5312d72003-02-21 17:14:10 +00006544/**
6545 * xmlRelaxNGCleanupDoc:
6546 * @ctxt: a Relax-NG parser context
6547 * @doc: an xmldocPtr document pointer
6548 *
6549 * Cleanup the document from unwanted nodes for parsing, resolve
6550 * Include and externalRef lookups.
6551 *
6552 * Returns the cleaned up document or NULL in case of error
6553 */
6554static xmlDocPtr
6555xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6556 xmlNodePtr root;
6557
6558 /*
6559 * Extract the root
6560 */
6561 root = xmlDocGetRootElement(doc);
6562 if (root == NULL) {
6563 if (ctxt->error != NULL)
6564 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6565 ctxt->URL);
6566 ctxt->nbErrors++;
6567 return (NULL);
6568 }
6569 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006570 return(doc);
6571}
6572
6573/**
6574 * xmlRelaxNGParse:
6575 * @ctxt: a Relax-NG parser context
6576 *
6577 * parse a schema definition resource and build an internal
6578 * XML Shema struture which can be used to validate instances.
6579 * *WARNING* this interface is highly subject to change
6580 *
6581 * Returns the internal XML RelaxNG structure built from the resource or
6582 * NULL in case of error
6583 */
6584xmlRelaxNGPtr
6585xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6586{
6587 xmlRelaxNGPtr ret = NULL;
6588 xmlDocPtr doc;
6589 xmlNodePtr root;
6590
6591 xmlRelaxNGInitTypes();
6592
6593 if (ctxt == NULL)
6594 return (NULL);
6595
6596 /*
6597 * First step is to parse the input document into an DOM/Infoset
6598 */
6599 if (ctxt->URL != NULL) {
6600 doc = xmlParseFile((const char *) ctxt->URL);
6601 if (doc == NULL) {
6602 if (ctxt->error != NULL)
6603 ctxt->error(ctxt->userData,
6604 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6605 ctxt->nbErrors++;
6606 return (NULL);
6607 }
6608 } else if (ctxt->buffer != NULL) {
6609 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6610 if (doc == NULL) {
6611 if (ctxt->error != NULL)
6612 ctxt->error(ctxt->userData,
6613 "xmlRelaxNGParse: could not parse schemas\n");
6614 ctxt->nbErrors++;
6615 return (NULL);
6616 }
6617 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6618 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6619 } else {
6620 if (ctxt->error != NULL)
6621 ctxt->error(ctxt->userData,
6622 "xmlRelaxNGParse: nothing to parse\n");
6623 ctxt->nbErrors++;
6624 return (NULL);
6625 }
6626 ctxt->document = doc;
6627
6628 /*
6629 * Some preprocessing of the document content
6630 */
6631 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6632 if (doc == NULL) {
6633 xmlFreeDoc(ctxt->document);
6634 ctxt->document = NULL;
6635 return(NULL);
6636 }
6637
Daniel Veillard6eadf632003-01-23 18:29:16 +00006638 /*
6639 * Then do the parsing for good
6640 */
6641 root = xmlDocGetRootElement(doc);
6642 if (root == NULL) {
6643 if (ctxt->error != NULL)
6644 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6645 ctxt->URL);
6646 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006647 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006648 return (NULL);
6649 }
6650 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006651 if (ret == NULL) {
6652 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006653 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006654 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006655
6656 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006657 * Check the ref/defines links
6658 */
6659 /*
6660 * try to preprocess interleaves
6661 */
6662 if (ctxt->interleaves != NULL) {
6663 xmlHashScan(ctxt->interleaves,
6664 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6665 }
6666
6667 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006668 * if there was a parsing error return NULL
6669 */
6670 if (ctxt->nbErrors > 0) {
6671 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006672 ctxt->document = NULL;
6673 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006674 return(NULL);
6675 }
6676
6677 /*
6678 * Transfer the pointer for cleanup at the schema level.
6679 */
6680 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006681 ctxt->document = NULL;
6682 ret->documents = ctxt->documents;
6683 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006684
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006685 ret->includes = ctxt->includes;
6686 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006687 ret->defNr = ctxt->defNr;
6688 ret->defTab = ctxt->defTab;
6689 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006690 if (ctxt->idref == 1)
6691 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006692
6693 return (ret);
6694}
6695
6696/**
6697 * xmlRelaxNGSetParserErrors:
6698 * @ctxt: a Relax-NG validation context
6699 * @err: the error callback
6700 * @warn: the warning callback
6701 * @ctx: contextual data for the callbacks
6702 *
6703 * Set the callback functions used to handle errors for a validation context
6704 */
6705void
6706xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6707 xmlRelaxNGValidityErrorFunc err,
6708 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6709 if (ctxt == NULL)
6710 return;
6711 ctxt->error = err;
6712 ctxt->warning = warn;
6713 ctxt->userData = ctx;
6714}
6715/************************************************************************
6716 * *
6717 * Dump back a compiled form *
6718 * *
6719 ************************************************************************/
6720static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6721
6722/**
6723 * xmlRelaxNGDumpDefines:
6724 * @output: the file output
6725 * @defines: a list of define structures
6726 *
6727 * Dump a RelaxNG structure back
6728 */
6729static void
6730xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6731 while (defines != NULL) {
6732 xmlRelaxNGDumpDefine(output, defines);
6733 defines = defines->next;
6734 }
6735}
6736
6737/**
6738 * xmlRelaxNGDumpDefine:
6739 * @output: the file output
6740 * @define: a define structure
6741 *
6742 * Dump a RelaxNG structure back
6743 */
6744static void
6745xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6746 if (define == NULL)
6747 return;
6748 switch(define->type) {
6749 case XML_RELAXNG_EMPTY:
6750 fprintf(output, "<empty/>\n");
6751 break;
6752 case XML_RELAXNG_NOT_ALLOWED:
6753 fprintf(output, "<notAllowed/>\n");
6754 break;
6755 case XML_RELAXNG_TEXT:
6756 fprintf(output, "<text/>\n");
6757 break;
6758 case XML_RELAXNG_ELEMENT:
6759 fprintf(output, "<element>\n");
6760 if (define->name != NULL) {
6761 fprintf(output, "<name");
6762 if (define->ns != NULL)
6763 fprintf(output, " ns=\"%s\"", define->ns);
6764 fprintf(output, ">%s</name>\n", define->name);
6765 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006766 xmlRelaxNGDumpDefines(output, define->attrs);
6767 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006768 fprintf(output, "</element>\n");
6769 break;
6770 case XML_RELAXNG_LIST:
6771 fprintf(output, "<list>\n");
6772 xmlRelaxNGDumpDefines(output, define->content);
6773 fprintf(output, "</list>\n");
6774 break;
6775 case XML_RELAXNG_ONEORMORE:
6776 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006777 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006778 fprintf(output, "</oneOrMore>\n");
6779 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006780 case XML_RELAXNG_ZEROORMORE:
6781 fprintf(output, "<zeroOrMore>\n");
6782 xmlRelaxNGDumpDefines(output, define->content);
6783 fprintf(output, "</zeroOrMore>\n");
6784 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006785 case XML_RELAXNG_CHOICE:
6786 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006787 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006788 fprintf(output, "</choice>\n");
6789 break;
6790 case XML_RELAXNG_GROUP:
6791 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006792 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006793 fprintf(output, "</group>\n");
6794 break;
6795 case XML_RELAXNG_INTERLEAVE:
6796 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006797 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006798 fprintf(output, "</interleave>\n");
6799 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006800 case XML_RELAXNG_OPTIONAL:
6801 fprintf(output, "<optional>\n");
6802 xmlRelaxNGDumpDefines(output, define->content);
6803 fprintf(output, "</optional>\n");
6804 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006805 case XML_RELAXNG_ATTRIBUTE:
6806 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006807 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006808 fprintf(output, "</attribute>\n");
6809 break;
6810 case XML_RELAXNG_DEF:
6811 fprintf(output, "<define");
6812 if (define->name != NULL)
6813 fprintf(output, " name=\"%s\"", define->name);
6814 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006815 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006816 fprintf(output, "</define>\n");
6817 break;
6818 case XML_RELAXNG_REF:
6819 fprintf(output, "<ref");
6820 if (define->name != NULL)
6821 fprintf(output, " name=\"%s\"", define->name);
6822 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006823 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006824 fprintf(output, "</ref>\n");
6825 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006826 case XML_RELAXNG_PARENTREF:
6827 fprintf(output, "<parentRef");
6828 if (define->name != NULL)
6829 fprintf(output, " name=\"%s\"", define->name);
6830 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006831 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006832 fprintf(output, "</parentRef>\n");
6833 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006834 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006835 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006836 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006837 fprintf(output, "</externalRef>\n");
6838 break;
6839 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006840 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006841 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006842 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006843 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006844 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006845 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006846 TODO
6847 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006848 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006849 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006850 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006851 }
6852}
6853
6854/**
6855 * xmlRelaxNGDumpGrammar:
6856 * @output: the file output
6857 * @grammar: a grammar structure
6858 * @top: is this a top grammar
6859 *
6860 * Dump a RelaxNG structure back
6861 */
6862static void
6863xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6864{
6865 if (grammar == NULL)
6866 return;
6867
6868 fprintf(output, "<grammar");
6869 if (top)
6870 fprintf(output,
6871 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6872 switch(grammar->combine) {
6873 case XML_RELAXNG_COMBINE_UNDEFINED:
6874 break;
6875 case XML_RELAXNG_COMBINE_CHOICE:
6876 fprintf(output, " combine=\"choice\"");
6877 break;
6878 case XML_RELAXNG_COMBINE_INTERLEAVE:
6879 fprintf(output, " combine=\"interleave\"");
6880 break;
6881 default:
6882 fprintf(output, " <!-- invalid combine value -->");
6883 }
6884 fprintf(output, ">\n");
6885 if (grammar->start == NULL) {
6886 fprintf(output, " <!-- grammar had no start -->");
6887 } else {
6888 fprintf(output, "<start>\n");
6889 xmlRelaxNGDumpDefine(output, grammar->start);
6890 fprintf(output, "</start>\n");
6891 }
6892 /* TODO ? Dump the defines ? */
6893 fprintf(output, "</grammar>\n");
6894}
6895
6896/**
6897 * xmlRelaxNGDump:
6898 * @output: the file output
6899 * @schema: a schema structure
6900 *
6901 * Dump a RelaxNG structure back
6902 */
6903void
6904xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6905{
6906 if (schema == NULL) {
6907 fprintf(output, "RelaxNG empty or failed to compile\n");
6908 return;
6909 }
6910 fprintf(output, "RelaxNG: ");
6911 if (schema->doc == NULL) {
6912 fprintf(output, "no document\n");
6913 } else if (schema->doc->URL != NULL) {
6914 fprintf(output, "%s\n", schema->doc->URL);
6915 } else {
6916 fprintf(output, "\n");
6917 }
6918 if (schema->topgrammar == NULL) {
6919 fprintf(output, "RelaxNG has no top grammar\n");
6920 return;
6921 }
6922 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6923}
6924
Daniel Veillardfebcca42003-02-16 15:44:18 +00006925/**
6926 * xmlRelaxNGDumpTree:
6927 * @output: the file output
6928 * @schema: a schema structure
6929 *
6930 * Dump the transformed RelaxNG tree.
6931 */
6932void
6933xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6934{
6935 if (schema == NULL) {
6936 fprintf(output, "RelaxNG empty or failed to compile\n");
6937 return;
6938 }
6939 if (schema->doc == NULL) {
6940 fprintf(output, "no document\n");
6941 } else {
6942 xmlDocDump(output, schema->doc);
6943 }
6944}
6945
Daniel Veillard6eadf632003-01-23 18:29:16 +00006946/************************************************************************
6947 * *
6948 * Validation implementation *
6949 * *
6950 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006951static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6952 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006953static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6954 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006955
6956/**
6957 * xmlRelaxNGSkipIgnored:
6958 * @ctxt: a schema validation context
6959 * @node: the top node.
6960 *
6961 * Skip ignorable nodes in that context
6962 *
6963 * Returns the new sibling or NULL in case of error.
6964 */
6965static xmlNodePtr
6966xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6967 xmlNodePtr node) {
6968 /*
6969 * TODO complete and handle entities
6970 */
6971 while ((node != NULL) &&
6972 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006973 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006974 (((node->type == XML_TEXT_NODE) ||
6975 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00006976 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
6977 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006978 node = node->next;
6979 }
6980 return(node);
6981}
6982
6983/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006984 * xmlRelaxNGNormalize:
6985 * @ctxt: a schema validation context
6986 * @str: the string to normalize
6987 *
6988 * Implements the normalizeWhiteSpace( s ) function from
6989 * section 6.2.9 of the spec
6990 *
6991 * Returns the new string or NULL in case of error.
6992 */
6993static xmlChar *
6994xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6995 xmlChar *ret, *p;
6996 const xmlChar *tmp;
6997 int len;
6998
6999 if (str == NULL)
7000 return(NULL);
7001 tmp = str;
7002 while (*tmp != 0) tmp++;
7003 len = tmp - str;
7004
7005 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7006 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007007 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007008 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007009 } else {
7010 xmlGenericError(xmlGenericErrorContext,
7011 "xmlRelaxNGNormalize: out of memory\n");
7012 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007013 return(NULL);
7014 }
7015 p = ret;
7016 while (IS_BLANK(*str)) str++;
7017 while (*str != 0) {
7018 if (IS_BLANK(*str)) {
7019 while (IS_BLANK(*str)) str++;
7020 if (*str == 0)
7021 break;
7022 *p++ = ' ';
7023 } else
7024 *p++ = *str++;
7025 }
7026 *p = 0;
7027 return(ret);
7028}
7029
7030/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007031 * xmlRelaxNGValidateDatatype:
7032 * @ctxt: a Relax-NG validation context
7033 * @value: the string value
7034 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007035 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007036 *
7037 * Validate the given value against the dataype
7038 *
7039 * Returns 0 if the validation succeeded or an error code.
7040 */
7041static int
7042xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007043 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007044 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007045 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007046 void *result = NULL;
7047 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007048
7049 if ((define == NULL) || (define->data == NULL)) {
7050 return(-1);
7051 }
7052 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007053 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007054 if ((define->attrs != NULL) &&
7055 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007056 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007057 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007058 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007059 }
7060 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007061 ret = -1;
7062 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007063 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007064 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7065 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007066 return(-1);
7067 } else if (ret == 1) {
7068 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007069 } else if (ret == 2) {
7070 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007071 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007072 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007073 ret = -1;
7074 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007075 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007076 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7077 if (lib->facet != NULL) {
7078 tmp = lib->facet(lib->data, define->name, cur->name,
7079 cur->value, value, result);
7080 if (tmp != 0)
7081 ret = -1;
7082 }
7083 cur = cur->next;
7084 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007085 if ((ret == 0) && (define->content != NULL)) {
7086 const xmlChar *oldvalue, *oldendvalue;
7087
7088 oldvalue = ctxt->state->value;
7089 oldendvalue = ctxt->state->endvalue;
7090 ctxt->state->value = (xmlChar *) value;
7091 ctxt->state->endvalue = NULL;
7092 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7093 ctxt->state->value = (xmlChar *) oldvalue;
7094 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7095 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007096 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7097 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007098 return(ret);
7099}
7100
7101/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007102 * xmlRelaxNGNextValue:
7103 * @ctxt: a Relax-NG validation context
7104 *
7105 * Skip to the next value when validating within a list
7106 *
7107 * Returns 0 if the operation succeeded or an error code.
7108 */
7109static int
7110xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7111 xmlChar *cur;
7112
7113 cur = ctxt->state->value;
7114 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7115 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007116 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007117 return(0);
7118 }
7119 while (*cur != 0) cur++;
7120 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7121 if (cur == ctxt->state->endvalue)
7122 ctxt->state->value = NULL;
7123 else
7124 ctxt->state->value = cur;
7125 return(0);
7126}
7127
7128/**
7129 * xmlRelaxNGValidateValueList:
7130 * @ctxt: a Relax-NG validation context
7131 * @defines: the list of definitions to verify
7132 *
7133 * Validate the given set of definitions for the current value
7134 *
7135 * Returns 0 if the validation succeeded or an error code.
7136 */
7137static int
7138xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7139 xmlRelaxNGDefinePtr defines) {
7140 int ret = 0;
7141
7142 while (defines != NULL) {
7143 ret = xmlRelaxNGValidateValue(ctxt, defines);
7144 if (ret != 0)
7145 break;
7146 defines = defines->next;
7147 }
7148 return(ret);
7149}
7150
7151/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007152 * xmlRelaxNGValidateValue:
7153 * @ctxt: a Relax-NG validation context
7154 * @define: the definition to verify
7155 *
7156 * Validate the given definition for the current value
7157 *
7158 * Returns 0 if the validation succeeded or an error code.
7159 */
7160static int
7161xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7162 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007163 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007164 xmlChar *value;
7165
7166 value = ctxt->state->value;
7167 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007168 case XML_RELAXNG_EMPTY: {
7169 if ((value != NULL) && (value[0] != 0)) {
7170 int idx = 0;
7171
7172 while (IS_BLANK(value[idx]))
7173 idx++;
7174 if (value[idx] != 0)
7175 ret = -1;
7176 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007177 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007178 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007179 case XML_RELAXNG_TEXT:
7180 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007181 case XML_RELAXNG_VALUE: {
7182 if (!xmlStrEqual(value, define->value)) {
7183 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007184 xmlRelaxNGTypeLibraryPtr lib;
7185
7186 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
7187 if ((lib != NULL) && (lib->comp != NULL))
7188 ret = lib->comp(lib->data, define->name, value,
7189 define->value);
7190 else
7191 ret = -1;
7192 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007193 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007194 return(-1);
7195 } else if (ret == 1) {
7196 ret = 0;
7197 } else {
7198 ret = -1;
7199 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007200 } else {
7201 xmlChar *nval, *nvalue;
7202
7203 /*
7204 * TODO: trivial optimizations are possible by
7205 * computing at compile-time
7206 */
7207 nval = xmlRelaxNGNormalize(ctxt, define->value);
7208 nvalue = xmlRelaxNGNormalize(ctxt, value);
7209
Daniel Veillardea3f3982003-01-26 19:45:18 +00007210 if ((nval == NULL) || (nvalue == NULL) ||
7211 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007212 ret = -1;
7213 if (nval != NULL)
7214 xmlFree(nval);
7215 if (nvalue != NULL)
7216 xmlFree(nvalue);
7217 }
7218 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007219 if (ret == 0)
7220 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007221 break;
7222 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007223 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007224 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7225 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007226 if (ret == 0)
7227 xmlRelaxNGNextValue(ctxt);
7228
7229 break;
7230 }
7231 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007232 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007233 xmlChar *oldvalue;
7234
7235 oldflags = ctxt->flags;
7236 ctxt->flags |= FLAGS_IGNORABLE;
7237
7238 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007239 while (list != NULL) {
7240 ret = xmlRelaxNGValidateValue(ctxt, list);
7241 if (ret == 0) {
7242 break;
7243 }
7244 ctxt->state->value = oldvalue;
7245 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007246 }
7247 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007248 if (ret != 0) {
7249 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7250 xmlRelaxNGDumpValidError(ctxt);
7251 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007252 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007253 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007254 if (ret == 0)
7255 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007256 break;
7257 }
7258 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007259 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007260 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007261#ifdef DEBUG_LIST
7262 int nb_values = 0;
7263#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007264
7265 oldvalue = ctxt->state->value;
7266 oldend = ctxt->state->endvalue;
7267
7268 val = xmlStrdup(oldvalue);
7269 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007270 val = xmlStrdup(BAD_CAST "");
7271 }
7272 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007273 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007274 return(-1);
7275 }
7276 cur = val;
7277 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007278 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007279 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007280 cur++;
7281#ifdef DEBUG_LIST
7282 nb_values++;
7283#endif
7284 while (IS_BLANK(*cur))
7285 *cur++ = 0;
7286 } else
7287 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007288 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007289#ifdef DEBUG_LIST
7290 xmlGenericError(xmlGenericErrorContext,
7291 "list value: '%s' found %d items\n", oldvalue, nb_values);
7292 nb_values = 0;
7293#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007294 ctxt->state->endvalue = cur;
7295 cur = val;
7296 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007297
Daniel Veillardfd573f12003-03-16 17:52:32 +00007298 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007299
Daniel Veillardfd573f12003-03-16 17:52:32 +00007300 while (list != NULL) {
7301 if (ctxt->state->value == ctxt->state->endvalue)
7302 ctxt->state->value = NULL;
7303 ret = xmlRelaxNGValidateValue(ctxt, list);
7304 if (ret != 0) {
7305#ifdef DEBUG_LIST
7306 xmlGenericError(xmlGenericErrorContext,
7307 "Failed to validate value: '%s' with %d rule\n",
7308 ctxt->state->value, nb_values);
7309#endif
7310 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007311 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007312#ifdef DEBUG_LIST
7313 nb_values++;
7314#endif
7315 list = list->next;
7316 }
7317
7318 if ((ret == 0) && (ctxt->state->value != NULL) &&
7319 (ctxt->state->value != ctxt->state->endvalue)) {
7320 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7321 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007322 }
7323 xmlFree(val);
7324 ctxt->state->value = oldvalue;
7325 ctxt->state->endvalue = oldend;
7326 break;
7327 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007328 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007329 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7330 if (ret != 0) {
7331 break;
7332 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007333 /* no break on purpose */
7334 case XML_RELAXNG_ZEROORMORE: {
7335 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007336
7337 oldflags = ctxt->flags;
7338 ctxt->flags |= FLAGS_IGNORABLE;
7339 cur = ctxt->state->value;
7340 temp = NULL;
7341 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7342 (temp != cur)) {
7343 temp = cur;
7344 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7345 if (ret != 0) {
7346 ctxt->state->value = temp;
7347 ret = 0;
7348 break;
7349 }
7350 cur = ctxt->state->value;
7351 }
7352 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007353 if (ret != 0) {
7354 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7355 xmlRelaxNGDumpValidError(ctxt);
7356 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007357 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007358 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007359 break;
7360 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007361 case XML_RELAXNG_EXCEPT: {
7362 xmlRelaxNGDefinePtr list;
7363
7364 list = define->content;
7365 while (list != NULL) {
7366 ret = xmlRelaxNGValidateValue(ctxt, list);
7367 if (ret == 0) {
7368 ret = -1;
7369 break;
7370 } else
7371 ret = 0;
7372 list = list->next;
7373 }
7374 break;
7375 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007376 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007377 case XML_RELAXNG_GROUP: {
7378 xmlRelaxNGDefinePtr list;
7379
7380 list = define->content;
7381 while (list != NULL) {
7382 ret = xmlRelaxNGValidateValue(ctxt, list);
7383 if (ret != 0) {
7384 ret = -1;
7385 break;
7386 } else
7387 ret = 0;
7388 list = list->next;
7389 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007390 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007391 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007392 case XML_RELAXNG_REF:
7393 case XML_RELAXNG_PARENTREF:
7394 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7395 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007396 default:
7397 TODO
7398 ret = -1;
7399 }
7400 return(ret);
7401}
7402
7403/**
7404 * xmlRelaxNGValidateValueContent:
7405 * @ctxt: a Relax-NG validation context
7406 * @defines: the list of definitions to verify
7407 *
7408 * Validate the given definitions for the current value
7409 *
7410 * Returns 0 if the validation succeeded or an error code.
7411 */
7412static int
7413xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7414 xmlRelaxNGDefinePtr defines) {
7415 int ret = 0;
7416
7417 while (defines != NULL) {
7418 ret = xmlRelaxNGValidateValue(ctxt, defines);
7419 if (ret != 0)
7420 break;
7421 defines = defines->next;
7422 }
7423 return(ret);
7424}
7425
7426/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007427 * xmlRelaxNGAttributeMatch:
7428 * @ctxt: a Relax-NG validation context
7429 * @define: the definition to check
7430 * @prop: the attribute
7431 *
7432 * Check if the attribute matches the definition nameClass
7433 *
7434 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7435 */
7436static int
7437xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7438 xmlRelaxNGDefinePtr define,
7439 xmlAttrPtr prop) {
7440 int ret;
7441
7442 if (define->name != NULL) {
7443 if (!xmlStrEqual(define->name, prop->name))
7444 return(0);
7445 }
7446 if (define->ns != NULL) {
7447 if (define->ns[0] == 0) {
7448 if (prop->ns != NULL)
7449 return(0);
7450 } else {
7451 if ((prop->ns == NULL) ||
7452 (!xmlStrEqual(define->ns, prop->ns->href)))
7453 return(0);
7454 }
7455 }
7456 if (define->nameClass == NULL)
7457 return(1);
7458 define = define->nameClass;
7459 if (define->type == XML_RELAXNG_EXCEPT) {
7460 xmlRelaxNGDefinePtr list;
7461
7462 list = define->content;
7463 while (list != NULL) {
7464 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7465 if (ret == 1)
7466 return(0);
7467 if (ret < 0)
7468 return(ret);
7469 list = list->next;
7470 }
7471 } else {
7472 TODO
7473 }
7474 return(1);
7475}
7476
7477/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007478 * xmlRelaxNGValidateAttribute:
7479 * @ctxt: a Relax-NG validation context
7480 * @define: the definition to verify
7481 *
7482 * Validate the given attribute definition for that node
7483 *
7484 * Returns 0 if the validation succeeded or an error code.
7485 */
7486static int
7487xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7488 xmlRelaxNGDefinePtr define) {
7489 int ret = 0, i;
7490 xmlChar *value, *oldvalue;
7491 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007492 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007493
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007494 if (ctxt->state->nbAttrLeft <= 0)
7495 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007496 if (define->name != NULL) {
7497 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7498 tmp = ctxt->state->attrs[i];
7499 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7500 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7501 (tmp->ns == NULL)) ||
7502 ((tmp->ns != NULL) &&
7503 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7504 prop = tmp;
7505 break;
7506 }
7507 }
7508 }
7509 if (prop != NULL) {
7510 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7511 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007512 oldseq = ctxt->state->seq;
7513 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007514 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007515 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007516 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007517 if (ctxt->state->value != NULL)
7518 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007519 if (value != NULL)
7520 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007521 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007522 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007523 if (ret == 0) {
7524 /*
7525 * flag the attribute as processed
7526 */
7527 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007528 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007529 }
7530 } else {
7531 ret = -1;
7532 }
7533#ifdef DEBUG
7534 xmlGenericError(xmlGenericErrorContext,
7535 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7536#endif
7537 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007538 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7539 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007540 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007541 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007542 prop = tmp;
7543 break;
7544 }
7545 }
7546 if (prop != NULL) {
7547 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7548 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007549 oldseq = ctxt->state->seq;
7550 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007551 ctxt->state->value = value;
7552 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007553 if (ctxt->state->value != NULL)
7554 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007555 if (value != NULL)
7556 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007557 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007558 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007559 if (ret == 0) {
7560 /*
7561 * flag the attribute as processed
7562 */
7563 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007564 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007565 }
7566 } else {
7567 ret = -1;
7568 }
7569#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007570 if (define->ns != NULL) {
7571 xmlGenericError(xmlGenericErrorContext,
7572 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7573 define->ns, ret);
7574 } else {
7575 xmlGenericError(xmlGenericErrorContext,
7576 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7577 ret);
7578 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007579#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007580 }
7581
7582 return(ret);
7583}
7584
7585/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007586 * xmlRelaxNGValidateAttributeList:
7587 * @ctxt: a Relax-NG validation context
7588 * @define: the list of definition to verify
7589 *
7590 * Validate the given node against the list of attribute definitions
7591 *
7592 * Returns 0 if the validation succeeded or an error code.
7593 */
7594static int
7595xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7596 xmlRelaxNGDefinePtr defines) {
7597 int ret = 0;
7598 while (defines != NULL) {
7599 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7600 ret = -1;
7601 defines = defines->next;
7602 }
7603 return(ret);
7604}
7605
7606/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007607 * xmlRelaxNGNodeMatchesList:
7608 * @node: the node
7609 * @list: a NULL terminated array of definitions
7610 *
7611 * Check if a node can be matched by one of the definitions
7612 *
7613 * Returns 1 if matches 0 otherwise
7614 */
7615static int
7616xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7617 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007618 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007619
7620 if ((node == NULL) || (list == NULL))
7621 return(0);
7622
7623 cur = list[i++];
7624 while (cur != NULL) {
7625 if ((node->type == XML_ELEMENT_NODE) &&
7626 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007627 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
7628 if (tmp == 1)
7629 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007630 } else if (((node->type == XML_TEXT_NODE) ||
7631 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007632 (cur->type == XML_RELAXNG_TEXT)) {
7633 return(1);
7634 }
7635 cur = list[i++];
7636 }
7637 return(0);
7638}
7639
7640/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007641 * xmlRelaxNGValidateInterleave:
7642 * @ctxt: a Relax-NG validation context
7643 * @define: the definition to verify
7644 *
7645 * Validate an interleave definition for a node.
7646 *
7647 * Returns 0 if the validation succeeded or an error code.
7648 */
7649static int
7650xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7651 xmlRelaxNGDefinePtr define) {
7652 int ret = 0, i, nbgroups, left;
7653 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007654 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007655
7656 xmlRelaxNGValidStatePtr oldstate;
7657 xmlRelaxNGPartitionPtr partitions;
7658 xmlRelaxNGInterleaveGroupPtr group = NULL;
7659 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7660 xmlNodePtr *list = NULL, *lasts = NULL;
7661
7662 if (define->data != NULL) {
7663 partitions = (xmlRelaxNGPartitionPtr) define->data;
7664 nbgroups = partitions->nbgroups;
7665 left = nbgroups;
7666 } else {
7667 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7668 return(-1);
7669 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007670 /*
7671 * Optimizations for MIXED
7672 */
7673 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00007674 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007675 ctxt->flags |= FLAGS_MIXED_CONTENT;
7676 if (nbgroups == 2) {
7677 /*
7678 * this is a pure <mixed> case
7679 */
7680 if (ctxt->state != NULL)
7681 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7682 ctxt->state->seq);
7683 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7684 ret = xmlRelaxNGValidateDefinition(ctxt,
7685 partitions->groups[1]->rule);
7686 else
7687 ret = xmlRelaxNGValidateDefinition(ctxt,
7688 partitions->groups[0]->rule);
7689 if (ret == 0) {
7690 if (ctxt->state != NULL)
7691 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7692 ctxt->state->seq);
7693 }
7694 ctxt->flags = oldflags;
7695 return(ret);
7696 }
7697 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007698
7699 /*
7700 * Build arrays to store the first and last node of the chain
7701 * pertaining to each group
7702 */
7703 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7704 if (list == NULL) {
7705 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7706 return(-1);
7707 }
7708 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7709 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7710 if (lasts == NULL) {
7711 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7712 return(-1);
7713 }
7714 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7715
7716 /*
7717 * Walk the sequence of children finding the right group and
7718 * sorting them in sequences.
7719 */
7720 cur = ctxt->state->seq;
7721 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7722 start = cur;
7723 while (cur != NULL) {
7724 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007725 if ((partitions->triage != NULL) &&
7726 (partitions->flags & IS_DETERMINIST)) {
7727 void *tmp = NULL;
7728
7729 if ((cur->type == XML_TEXT_NODE) ||
7730 (cur->type == XML_CDATA_SECTION_NODE)) {
7731 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7732 NULL);
7733 } else if (cur->type == XML_ELEMENT_NODE) {
7734 if (cur->ns != NULL) {
7735 tmp = xmlHashLookup2(partitions->triage, cur->name,
7736 cur->ns->href);
7737 if (tmp == NULL)
7738 tmp = xmlHashLookup2(partitions->triage,
7739 BAD_CAST "#any", cur->ns->href);
7740 } else
7741 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7742 if (tmp == NULL)
7743 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7744 NULL);
7745 }
7746
7747 if (tmp == NULL) {
7748 i = nbgroups;
7749 } else {
7750 i = ((long) tmp) - 1;
7751 if (partitions->flags & IS_NEEDCHECK) {
7752 group = partitions->groups[i];
7753 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7754 i = nbgroups;
7755 }
7756 }
7757 } else {
7758 for (i = 0;i < nbgroups;i++) {
7759 group = partitions->groups[i];
7760 if (group == NULL)
7761 continue;
7762 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7763 break;
7764 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007765 }
7766 /*
7767 * We break as soon as an element not matched is found
7768 */
7769 if (i >= nbgroups) {
7770 break;
7771 }
7772 if (lasts[i] != NULL) {
7773 lasts[i]->next = cur;
7774 lasts[i] = cur;
7775 } else {
7776 list[i] = cur;
7777 lasts[i] = cur;
7778 }
7779 if (cur->next != NULL)
7780 lastchg = cur->next;
7781 else
7782 lastchg = cur;
7783 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7784 }
7785 if (ret != 0) {
7786 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7787 ret = -1;
7788 goto done;
7789 }
7790 lastelem = cur;
7791 oldstate = ctxt->state;
7792 for (i = 0;i < nbgroups;i++) {
7793 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7794 group = partitions->groups[i];
7795 if (lasts[i] != NULL) {
7796 last = lasts[i]->next;
7797 lasts[i]->next = NULL;
7798 }
7799 ctxt->state->seq = list[i];
7800 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7801 if (ret != 0)
7802 break;
7803 if (ctxt->state != NULL) {
7804 cur = ctxt->state->seq;
7805 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007806 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007807 oldstate = ctxt->state;
7808 ctxt->state = NULL;
7809 if (cur != NULL) {
7810 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7811 ret = -1;
7812 ctxt->state = oldstate;
7813 goto done;
7814 }
7815 } else if (ctxt->states != NULL) {
7816 int j;
7817 int found = 0;
7818
7819 for (j = 0;j < ctxt->states->nbState;j++) {
7820 cur = ctxt->states->tabState[j]->seq;
7821 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7822 if (cur == NULL) {
7823 found = 1;
7824 break;
7825 }
7826 }
7827 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007828 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007829 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7830 }
7831 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007832 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007833 }
7834 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7835 ctxt->states = NULL;
7836 if (found == 0) {
7837 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7838 ret = -1;
7839 ctxt->state = oldstate;
7840 goto done;
7841 }
7842 } else {
7843 ret = -1;
7844 break;
7845 }
7846 if (lasts[i] != NULL) {
7847 lasts[i]->next = last;
7848 }
7849 }
7850 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007851 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007852 ctxt->state = oldstate;
7853 ctxt->state->seq = lastelem;
7854 if (ret != 0) {
7855 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7856 ret = -1;
7857 goto done;
7858 }
7859
7860done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007861 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007862 /*
7863 * builds the next links chain from the prev one
7864 */
7865 cur = lastchg;
7866 while (cur != NULL) {
7867 if ((cur == start) || (cur->prev == NULL))
7868 break;
7869 cur->prev->next = cur;
7870 cur = cur->prev;
7871 }
7872 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007873 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007874 }
7875
7876 xmlFree(list);
7877 xmlFree(lasts);
7878 return(ret);
7879}
7880
7881/**
7882 * xmlRelaxNGValidateDefinitionList:
7883 * @ctxt: a Relax-NG validation context
7884 * @define: the list of definition to verify
7885 *
7886 * Validate the given node content against the (list) of definitions
7887 *
7888 * Returns 0 if the validation succeeded or an error code.
7889 */
7890static int
7891xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7892 xmlRelaxNGDefinePtr defines) {
7893 int ret = 0, res;
7894
7895
Daniel Veillard952379b2003-03-17 15:37:12 +00007896 if (defines == NULL) {
7897 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7898 return(-1);
7899 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007900 while (defines != NULL) {
7901 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7902 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7903 if (res < 0)
7904 ret = -1;
7905 } else {
7906 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7907 return(-1);
7908 }
7909 if (ret < 0)
7910 break;
7911 defines = defines->next;
7912 }
7913
7914 return(ret);
7915}
7916
7917/**
7918 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007919 * @ctxt: a Relax-NG validation context
7920 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007921 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007922 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007923 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007924 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007925 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007926 */
7927static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007928xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7929 xmlRelaxNGDefinePtr define,
7930 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00007931 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007932
Daniel Veillardfd573f12003-03-16 17:52:32 +00007933 if (define->name != NULL) {
7934 if (!xmlStrEqual(elem->name, define->name)) {
7935 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7936 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007937 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007938 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007939 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7940 if (elem->ns == NULL) {
7941 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7942 elem->name);
7943 return(0);
7944 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7945 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7946 elem->name, define->ns);
7947 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007948 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007949 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7950 (define->name == NULL)) {
7951 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7952 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007953 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007954 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7955 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7956 define->name);
7957 return(0);
7958 }
7959
7960 if (define->nameClass == NULL)
7961 return(1);
7962
7963 define = define->nameClass;
7964 if (define->type == XML_RELAXNG_EXCEPT) {
7965 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007966 if (ctxt != NULL) {
7967 oldflags = ctxt->flags;
7968 ctxt->flags |= FLAGS_IGNORABLE;
7969 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007970
7971 list = define->content;
7972 while (list != NULL) {
7973 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7974 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007975 if (ctxt != NULL)
7976 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007977 return(0);
7978 }
7979 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007980 if (ctxt != NULL)
7981 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007982 return(ret);
7983 }
7984 list = list->next;
7985 }
7986 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007987 if (ctxt != NULL) {
7988 ctxt->flags = oldflags;
7989 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007990 } else if (define->type == XML_RELAXNG_CHOICE) {
7991 xmlRelaxNGDefinePtr list;
7992
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007993 if (ctxt != NULL) {
7994 oldflags = ctxt->flags;
7995 ctxt->flags |= FLAGS_IGNORABLE;
7996 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007997
7998 list = define->nameClass;
7999 while (list != NULL) {
8000 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8001 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008002 if (ctxt != NULL)
8003 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008004 return(1);
8005 }
8006 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008007 if (ctxt != NULL)
8008 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008009 return(ret);
8010 }
8011 list = list->next;
8012 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008013 if (ctxt != NULL) {
8014 if (ret != 0) {
8015 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8016 xmlRelaxNGDumpValidError(ctxt);
8017 } else {
8018 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8019 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008020 }
8021 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008022 if (ctxt != NULL) {
8023 ctxt->flags = oldflags;
8024 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008025 } else {
8026 TODO
8027 ret = -1;
8028 }
8029 return(ret);
8030}
8031
8032/**
8033 * xmlRelaxNGValidateElementEnd:
8034 * @ctxt: a Relax-NG validation context
8035 *
8036 * Validate the end of the element, implements check that
8037 * there is nothing left not consumed in the element content
8038 * or in the attribute list.
8039 *
8040 * Returns 0 if the validation succeeded or an error code.
8041 */
8042static int
8043xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8044 int ret = 0, i;
8045 xmlRelaxNGValidStatePtr state;
8046
8047 state = ctxt->state;
8048 if (state->seq != NULL) {
8049 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8050 if (state->seq != NULL) {
8051 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8052 state->node->name, state->seq->name);
8053 ret = -1;
8054 }
8055 }
8056 for (i = 0;i < state->nbAttrs;i++) {
8057 if (state->attrs[i] != NULL) {
8058 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8059 state->attrs[i]->name, state->node->name);
8060 ret = -1;
8061 }
8062 }
8063 return(ret);
8064}
8065
8066/**
8067 * xmlRelaxNGValidateState:
8068 * @ctxt: a Relax-NG validation context
8069 * @define: the definition to verify
8070 *
8071 * Validate the current state against the definition
8072 *
8073 * Returns 0 if the validation succeeded or an error code.
8074 */
8075static int
8076xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8077 xmlRelaxNGDefinePtr define) {
8078 xmlNodePtr node;
8079 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008080 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008081
8082 if (define == NULL) {
8083 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8084 return(-1);
8085 }
8086
8087 if (ctxt->state != NULL) {
8088 node = ctxt->state->seq;
8089 } else {
8090 node = NULL;
8091 }
8092#ifdef DEBUG
8093 for (i = 0;i < ctxt->depth;i++)
8094 xmlGenericError(xmlGenericErrorContext, " ");
8095 xmlGenericError(xmlGenericErrorContext,
8096 "Start validating %s ", xmlRelaxNGDefName(define));
8097 if (define->name != NULL)
8098 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8099 if ((node != NULL) && (node->name != NULL))
8100 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8101 else
8102 xmlGenericError(xmlGenericErrorContext, "\n");
8103#endif
8104 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008105 switch (define->type) {
8106 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008107 node = xmlRelaxNGSkipIgnored(ctxt, node);
8108 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008109 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008110 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008111 ret = -1;
8112 break;
8113 case XML_RELAXNG_TEXT:
8114 while ((node != NULL) &&
8115 ((node->type == XML_TEXT_NODE) ||
8116 (node->type == XML_COMMENT_NODE) ||
8117 (node->type == XML_PI_NODE) ||
8118 (node->type == XML_CDATA_SECTION_NODE)))
8119 node = node->next;
8120 ctxt->state->seq = node;
8121 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008122 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008123 errNr = ctxt->errNr;
8124 node = xmlRelaxNGSkipIgnored(ctxt, node);
8125 if (node == NULL) {
8126 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8127 ret = -1;
8128 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8129 xmlRelaxNGDumpValidError(ctxt);
8130 break;
8131 }
8132 if (node->type != XML_ELEMENT_NODE) {
8133 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8134 ret = -1;
8135 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8136 xmlRelaxNGDumpValidError(ctxt);
8137 break;
8138 }
8139 /*
8140 * This node was already validated successfully against
8141 * this definition.
8142 */
8143 if (node->_private == define) {
8144 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard580ced82003-03-21 21:22:48 +00008145 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008146 if (ctxt->errNr != 0) {
8147 while ((ctxt->err != NULL) &&
8148 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8149 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008150 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8151 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008152 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8153 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8154 xmlRelaxNGValidErrorPop(ctxt);
8155 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008156 break;
8157 }
8158
8159 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8160 if (ret <= 0) {
8161 ret = -1;
8162 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8163 xmlRelaxNGDumpValidError(ctxt);
8164 break;
8165 }
8166 ret = 0;
8167 if (ctxt->errNr != 0) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008168 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008169 while ((ctxt->err != NULL) &&
8170 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8171 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008172 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8173 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00008174 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8175 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8176 xmlRelaxNGValidErrorPop(ctxt);
8177 }
8178 errNr = ctxt->errNr;
8179
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008180 oldflags = ctxt->flags;
8181 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8182 ctxt->flags -= FLAGS_MIXED_CONTENT;
8183 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008184 state = xmlRelaxNGNewValidState(ctxt, node);
8185 if (state == NULL) {
8186 ret = -1;
8187 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8188 xmlRelaxNGDumpValidError(ctxt);
8189 break;
8190 }
8191
8192 oldstate = ctxt->state;
8193 ctxt->state = state;
8194 if (define->attrs != NULL) {
8195 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8196 if (tmp != 0) {
8197 ret = -1;
8198 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8199 }
8200 }
8201 if (define->content != NULL) {
8202 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8203 if (tmp != 0) {
8204 ret = -1;
8205 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8206 }
8207 }
8208 if (ctxt->states != NULL) {
8209 tmp = -1;
8210
Daniel Veillardfd573f12003-03-16 17:52:32 +00008211 ctxt->flags |= FLAGS_IGNORABLE;
8212
8213 for (i = 0;i < ctxt->states->nbState;i++) {
8214 state = ctxt->states->tabState[i];
8215 ctxt->state = state;
8216
8217 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8218 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008219 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008220 }
8221 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8222 ctxt->flags = oldflags;
8223 ctxt->states = NULL;
8224 if ((ret == 0) && (tmp == -1))
8225 ret = -1;
8226 } else {
8227 state = ctxt->state;
8228 if (ret == 0)
8229 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008230 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008231 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008232 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008233 ctxt->state = oldstate;
8234 if (oldstate != NULL)
8235 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8236 if (ret == 0) {
8237 node->_private = define;
8238 }
8239 if (ret != 0) {
8240 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8241 xmlRelaxNGDumpValidError(ctxt);
8242 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008243 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008244 }
8245
8246#ifdef DEBUG
8247 xmlGenericError(xmlGenericErrorContext,
8248 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8249 node->name, ret);
8250 if (oldstate == NULL)
8251 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8252 else if (oldstate->seq == NULL)
8253 xmlGenericError(xmlGenericErrorContext, ": done\n");
8254 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8255 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8256 oldstate->seq->name);
8257 else
8258 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8259 oldstate->seq->name, oldstate->seq->type);
8260#endif
8261 break;
8262 case XML_RELAXNG_OPTIONAL: {
8263 oldflags = ctxt->flags;
8264 ctxt->flags |= FLAGS_IGNORABLE;
8265 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8266 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8267 if (ret != 0) {
8268 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008269 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008270 ctxt->state = oldstate;
8271 ctxt->flags = oldflags;
8272 ret = 0;
8273 break;
8274 }
8275 if (ctxt->states != NULL) {
8276 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8277 } else {
8278 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8279 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008280 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008281 ctxt->flags = oldflags;
8282 ret = -1;
8283 break;
8284 }
8285 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8286 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8287 ctxt->state = NULL;
8288 }
8289 ctxt->flags = oldflags;
8290 ret = 0;
8291 break;
8292 }
8293 case XML_RELAXNG_ONEORMORE:
8294 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8295 if (ret != 0) {
8296 break;
8297 }
8298 /* no break on purpose */
8299 case XML_RELAXNG_ZEROORMORE: {
8300 int progress;
8301 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8302 int base, j;
8303
8304 res = xmlRelaxNGNewStates(ctxt, 1);
8305 if (res == NULL) {
8306 ret = -1;
8307 break;
8308 }
8309 /*
8310 * All the input states are also exit states
8311 */
8312 if (ctxt->state != NULL) {
8313 xmlRelaxNGAddStates(ctxt, res,
8314 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8315 } else {
8316 for (j = 0;j < ctxt->states->nbState;j++) {
8317 xmlRelaxNGAddStates(ctxt, res,
8318 xmlRelaxNGCopyValidState(ctxt,
8319 ctxt->states->tabState[j]));
8320 }
8321 }
8322 oldflags = ctxt->flags;
8323 ctxt->flags |= FLAGS_IGNORABLE;
8324 do {
8325 progress = 0;
8326 base = res->nbState;
8327
8328 if (ctxt->states != NULL) {
8329 states = ctxt->states;
8330 for (i = 0;i < states->nbState;i++) {
8331 ctxt->state = states->tabState[i];
8332 ctxt->states = NULL;
8333 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8334 define->content);
8335 if (ret == 0) {
8336 if (ctxt->state != NULL) {
8337 tmp = xmlRelaxNGAddStates(ctxt, res,
8338 ctxt->state);
8339 ctxt->state = NULL;
8340 if (tmp == 1)
8341 progress = 1;
8342 } else if (ctxt->states != NULL) {
8343 for (j = 0;j < ctxt->states->nbState;j++) {
8344 tmp = xmlRelaxNGAddStates(ctxt, res,
8345 ctxt->states->tabState[j]);
8346 if (tmp == 1)
8347 progress = 1;
8348 }
8349 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8350 ctxt->states = NULL;
8351 }
8352 } else {
8353 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008354 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008355 ctxt->state = NULL;
8356 }
8357 }
8358 }
8359 } else {
8360 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8361 define->content);
8362 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008363 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008364 ctxt->state = NULL;
8365 } else {
8366 base = res->nbState;
8367 if (ctxt->state != NULL) {
8368 tmp = xmlRelaxNGAddStates(ctxt, res,
8369 ctxt->state);
8370 ctxt->state = NULL;
8371 if (tmp == 1)
8372 progress = 1;
8373 } else if (ctxt->states != NULL) {
8374 for (j = 0;j < ctxt->states->nbState;j++) {
8375 tmp = xmlRelaxNGAddStates(ctxt, res,
8376 ctxt->states->tabState[j]);
8377 if (tmp == 1)
8378 progress = 1;
8379 }
8380 if (states == NULL) {
8381 states = ctxt->states;
8382 } else {
8383 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8384 }
8385 ctxt->states = NULL;
8386 }
8387 }
8388 }
8389 if (progress) {
8390 /*
8391 * Collect all the new nodes added at that step
8392 * and make them the new node set
8393 */
8394 if (res->nbState - base == 1) {
8395 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8396 res->tabState[base]);
8397 } else {
8398 if (states == NULL) {
8399 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8400 }
8401 states->nbState = 0;
8402 for (i = base;i < res->nbState;i++)
8403 xmlRelaxNGAddStates(ctxt, states,
8404 xmlRelaxNGCopyValidState(ctxt,
8405 res->tabState[i]));
8406 ctxt->states = states;
8407 }
8408 }
8409 } while (progress == 1);
8410 if (states != NULL) {
8411 xmlRelaxNGFreeStates(ctxt, states);
8412 }
8413 ctxt->states = res;
8414 ctxt->flags = oldflags;
8415 ret = 0;
8416 break;
8417 }
8418 case XML_RELAXNG_CHOICE: {
Daniel Veillard580ced82003-03-21 21:22:48 +00008419 xmlRelaxNGDefinePtr list = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008420 xmlRelaxNGStatesPtr states = NULL;
8421
Daniel Veillarde063f482003-03-21 16:53:17 +00008422 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008423
Daniel Veillarde063f482003-03-21 16:53:17 +00008424 if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
8425 xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
8426
8427 /*
8428 * Something we can optimize cleanly there is only one
8429 * possble branch out !
8430 */
8431 if (node == NULL) {
8432 ret = -1;
8433 break;
8434 }
8435 if ((node->type == XML_TEXT_NODE) ||
8436 (node->type == XML_CDATA_SECTION_NODE)) {
8437 list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
8438 } else if (node->type == XML_ELEMENT_NODE) {
8439 if (node->ns != NULL) {
8440 list = xmlHashLookup2(triage, node->name,
8441 node->ns->href);
8442 if (list == NULL)
8443 list = xmlHashLookup2(triage, BAD_CAST "#any",
8444 node->ns->href);
8445 } else
8446 list = xmlHashLookup2(triage, node->name, NULL);
8447 if (list == NULL)
8448 list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
8449 }
8450 if (list == NULL) {
8451 ret = -1;
8452 break;
8453 }
8454 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8455 break;
8456 }
8457
8458 list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008459 oldflags = ctxt->flags;
8460 errNr = ctxt->errNr;
8461 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008462
8463 while (list != NULL) {
8464 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8465 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8466 if (ret == 0) {
8467 if (states == NULL) {
8468 states = xmlRelaxNGNewStates(ctxt, 1);
8469 }
8470 if (ctxt->state != NULL) {
8471 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8472 } else if (ctxt->states != NULL) {
8473 for (i = 0;i < ctxt->states->nbState;i++) {
8474 xmlRelaxNGAddStates(ctxt, states,
8475 ctxt->states->tabState[i]);
8476 }
8477 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8478 ctxt->states = NULL;
8479 }
8480 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008481 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008482 }
8483 ctxt->state = oldstate;
8484 list = list->next;
8485 }
8486 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008487 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008488 ctxt->states = states;
8489 ctxt->state = NULL;
8490 ret = 0;
8491 } else {
8492 ctxt->states = NULL;
8493 }
8494 ctxt->flags = oldflags;
8495 if (ret != 0) {
8496 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8497 xmlRelaxNGDumpValidError(ctxt);
8498 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008499 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008500 }
8501 break;
8502 }
8503 case XML_RELAXNG_DEF:
8504 case XML_RELAXNG_GROUP:
8505 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008506 break;
8507 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008508 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008509 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008510 case XML_RELAXNG_ATTRIBUTE:
8511 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8512 break;
8513 case XML_RELAXNG_NOOP:
8514 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008515 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008516 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8517 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008518 case XML_RELAXNG_PARENTREF:
8519 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8520 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008521 case XML_RELAXNG_DATATYPE: {
8522 xmlNodePtr child;
8523 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008524
Daniel Veillardfd573f12003-03-16 17:52:32 +00008525 child = node;
8526 while (child != NULL) {
8527 if (child->type == XML_ELEMENT_NODE) {
8528 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8529 node->parent->name);
8530 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008531 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008532 } else if ((child->type == XML_TEXT_NODE) ||
8533 (child->type == XML_CDATA_SECTION_NODE)) {
8534 content = xmlStrcat(content, child->content);
8535 }
8536 /* TODO: handle entities ... */
8537 child = child->next;
8538 }
8539 if (ret == -1) {
8540 if (content != NULL)
8541 xmlFree(content);
8542 break;
8543 }
8544 if (content == NULL) {
8545 content = xmlStrdup(BAD_CAST "");
8546 if (content == NULL) {
8547 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8548 ret = -1;
8549 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008550 }
8551 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008552 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8553 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008554 if (ret == -1) {
8555 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8556 } else if (ret == 0) {
8557 ctxt->state->seq = NULL;
8558 }
8559 if (content != NULL)
8560 xmlFree(content);
8561 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008562 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008563 case XML_RELAXNG_VALUE: {
8564 xmlChar *content = NULL;
8565 xmlChar *oldvalue;
8566 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008567
Daniel Veillardfd573f12003-03-16 17:52:32 +00008568 child = node;
8569 while (child != NULL) {
8570 if (child->type == XML_ELEMENT_NODE) {
8571 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8572 node->parent->name);
8573 ret = -1;
8574 break;
8575 } else if ((child->type == XML_TEXT_NODE) ||
8576 (child->type == XML_CDATA_SECTION_NODE)) {
8577 content = xmlStrcat(content, child->content);
8578 }
8579 /* TODO: handle entities ... */
8580 child = child->next;
8581 }
8582 if (ret == -1) {
8583 if (content != NULL)
8584 xmlFree(content);
8585 break;
8586 }
8587 if (content == NULL) {
8588 content = xmlStrdup(BAD_CAST "");
8589 if (content == NULL) {
8590 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8591 ret = -1;
8592 break;
8593 }
8594 }
8595 oldvalue = ctxt->state->value;
8596 ctxt->state->value = content;
8597 ret = xmlRelaxNGValidateValue(ctxt, define);
8598 ctxt->state->value = oldvalue;
8599 if (ret == -1) {
8600 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8601 } else if (ret == 0) {
8602 ctxt->state->seq = NULL;
8603 }
8604 if (content != NULL)
8605 xmlFree(content);
8606 break;
8607 }
8608 case XML_RELAXNG_LIST: {
8609 xmlChar *content;
8610 xmlNodePtr child;
8611 xmlChar *oldvalue, *oldendvalue;
8612 int len;
8613
8614 /*
8615 * Make sure it's only text nodes
8616 */
8617
8618 content = NULL;
8619 child = node;
8620 while (child != NULL) {
8621 if (child->type == XML_ELEMENT_NODE) {
8622 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8623 node->parent->name);
8624 ret = -1;
8625 break;
8626 } else if ((child->type == XML_TEXT_NODE) ||
8627 (child->type == XML_CDATA_SECTION_NODE)) {
8628 content = xmlStrcat(content, child->content);
8629 }
8630 /* TODO: handle entities ... */
8631 child = child->next;
8632 }
8633 if (ret == -1) {
8634 if (content != NULL)
8635 xmlFree(content);
8636 break;
8637 }
8638 if (content == NULL) {
8639 content = xmlStrdup(BAD_CAST "");
8640 if (content == NULL) {
8641 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8642 ret = -1;
8643 break;
8644 }
8645 }
8646 len = xmlStrlen(content);
8647 oldvalue = ctxt->state->value;
8648 oldendvalue = ctxt->state->endvalue;
8649 ctxt->state->value = content;
8650 ctxt->state->endvalue = content + len;
8651 ret = xmlRelaxNGValidateValue(ctxt, define);
8652 ctxt->state->value = oldvalue;
8653 ctxt->state->endvalue = oldendvalue;
8654 if (ret == -1) {
8655 VALID_ERR(XML_RELAXNG_ERR_LIST);
8656 } else if ((ret == 0) && (node != NULL)) {
8657 ctxt->state->seq = node->next;
8658 }
8659 if (content != NULL)
8660 xmlFree(content);
8661 break;
8662 }
8663 case XML_RELAXNG_START:
8664 case XML_RELAXNG_EXCEPT:
8665 case XML_RELAXNG_PARAM:
8666 TODO
8667 ret = -1;
8668 break;
8669 }
8670 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008671#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008672 for (i = 0;i < ctxt->depth;i++)
8673 xmlGenericError(xmlGenericErrorContext, " ");
8674 xmlGenericError(xmlGenericErrorContext,
8675 "Validating %s ", xmlRelaxNGDefName(define));
8676 if (define->name != NULL)
8677 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8678 if (ret == 0)
8679 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8680 else
8681 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008682#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008683 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008684}
8685
8686/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008687 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008688 * @ctxt: a Relax-NG validation context
8689 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008690 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008691 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008692 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008693 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008694 */
8695static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008696xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8697 xmlRelaxNGDefinePtr define) {
8698 xmlRelaxNGStatesPtr states, res;
8699 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008700
Daniel Veillardfd573f12003-03-16 17:52:32 +00008701 /*
8702 * We should NOT have both ctxt->state and ctxt->states
8703 */
8704 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8705 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008706 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008707 ctxt->state = NULL;
8708 }
8709
8710 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8711 if (ctxt->states != NULL) {
8712 ctxt->state = ctxt->states->tabState[0];
8713 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8714 ctxt->states = NULL;
8715 }
8716 ret = xmlRelaxNGValidateState(ctxt, define);
8717 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8718 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008719 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008720 ctxt->state = NULL;
8721 }
8722 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8723 ctxt->state = ctxt->states->tabState[0];
8724 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8725 ctxt->states = NULL;
8726 }
8727 return(ret);
8728 }
8729
8730 states = ctxt->states;
8731 ctxt->states = NULL;
8732 res = NULL;
8733 j = 0;
8734 oldflags = ctxt->flags;
8735 ctxt->flags |= FLAGS_IGNORABLE;
8736 for (i = 0;i < states->nbState;i++) {
8737 ctxt->state = states->tabState[i];
8738 ctxt->states = NULL;
8739 ret = xmlRelaxNGValidateState(ctxt, define);
8740 /*
8741 * We should NOT have both ctxt->state and ctxt->states
8742 */
8743 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8744 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008745 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008746 ctxt->state = NULL;
8747 }
8748 if (ret == 0) {
8749 if (ctxt->states == NULL) {
8750 if (res != NULL) {
8751 /* add the state to the container */
8752 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8753 ctxt->state = NULL;
8754 } else {
8755 /* add the state directly in states */
8756 states->tabState[j++] = ctxt->state;
8757 ctxt->state = NULL;
8758 }
8759 } else {
8760 if (res == NULL) {
8761 /* make it the new container and copy other results */
8762 res = ctxt->states;
8763 ctxt->states = NULL;
8764 for (k = 0;k < j;k++)
8765 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8766 } else {
8767 /* add all the new results to res and reff the container */
8768 for (k = 0;k < ctxt->states->nbState;k++)
8769 xmlRelaxNGAddStates(ctxt, res,
8770 ctxt->states->tabState[k]);
8771 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8772 ctxt->states = NULL;
8773 }
8774 }
8775 } else {
8776 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008777 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008778 ctxt->state = NULL;
8779 } else if (ctxt->states != NULL) {
8780 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008781 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008782 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8783 ctxt->states = NULL;
8784 }
8785 }
8786 }
8787 ctxt->flags = oldflags;
8788 if (res != NULL) {
8789 xmlRelaxNGFreeStates(ctxt, states);
8790 ctxt->states = res;
8791 ret = 0;
8792 } else if (j > 1) {
8793 states->nbState = j;
8794 ctxt->states = states;
8795 ret =0;
8796 } else if (j == 1) {
8797 ctxt->state = states->tabState[0];
8798 xmlRelaxNGFreeStates(ctxt, states);
8799 ret = 0;
8800 } else {
8801 ret = -1;
8802 xmlRelaxNGFreeStates(ctxt, states);
8803 if (ctxt->states != NULL) {
8804 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8805 ctxt->states = NULL;
8806 }
8807 }
8808 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8809 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008810 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008811 ctxt->state = NULL;
8812 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008813 return(ret);
8814}
8815
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008816/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008817 * xmlRelaxNGValidateDocument:
8818 * @ctxt: a Relax-NG validation context
8819 * @doc: the document
8820 *
8821 * Validate the given document
8822 *
8823 * Returns 0 if the validation succeeded or an error code.
8824 */
8825static int
8826xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8827 int ret;
8828 xmlRelaxNGPtr schema;
8829 xmlRelaxNGGrammarPtr grammar;
8830 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008831 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008832
8833 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8834 return(-1);
8835
8836 schema = ctxt->schema;
8837 grammar = schema->topgrammar;
8838 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008839 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008840 return(-1);
8841 }
8842 state = xmlRelaxNGNewValidState(ctxt, NULL);
8843 ctxt->state = state;
8844 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008845 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8846 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008847 node = state->seq;
8848 node = xmlRelaxNGSkipIgnored(ctxt, node);
8849 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008850 if (ret != -1) {
8851 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8852 ret = -1;
8853 }
8854 }
8855 } else if (ctxt->states != NULL) {
8856 int i;
8857 int tmp = -1;
8858
8859 for (i = 0;i < ctxt->states->nbState;i++) {
8860 state = ctxt->states->tabState[i];
8861 node = state->seq;
8862 node = xmlRelaxNGSkipIgnored(ctxt, node);
8863 if (node == NULL)
8864 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008865 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008866 }
8867 if (tmp == -1) {
8868 if (ret != -1) {
8869 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8870 ret = -1;
8871 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008872 }
8873 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008874 if (ctxt->state != NULL) {
8875 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8876 ctxt->state = NULL;
8877 }
Daniel Veillard580ced82003-03-21 21:22:48 +00008878 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00008879 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00008880#ifdef DEBUG
8881 else if (ctxt->errNr != 0) {
8882 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
8883 ctxt->errNr);
8884 xmlRelaxNGDumpValidError(ctxt);
8885 }
8886#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008887 if (ctxt->idref == 1) {
8888 xmlValidCtxt vctxt;
8889
8890 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8891 vctxt.valid = 1;
8892 vctxt.error = ctxt->error;
8893 vctxt.warning = ctxt->warning;
8894 vctxt.userData = ctxt->userData;
8895
8896 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8897 ret = -1;
8898 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008899
8900 return(ret);
8901}
8902
Daniel Veillardfd573f12003-03-16 17:52:32 +00008903/************************************************************************
8904 * *
8905 * Validation interfaces *
8906 * *
8907 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008908/**
8909 * xmlRelaxNGNewValidCtxt:
8910 * @schema: a precompiled XML RelaxNGs
8911 *
8912 * Create an XML RelaxNGs validation context based on the given schema
8913 *
8914 * Returns the validation context or NULL in case of error
8915 */
8916xmlRelaxNGValidCtxtPtr
8917xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8918 xmlRelaxNGValidCtxtPtr ret;
8919
8920 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8921 if (ret == NULL) {
8922 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008923 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008924 return (NULL);
8925 }
8926 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8927 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008928 ret->error = xmlGenericError;
8929 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008930 ret->errNr = 0;
8931 ret->errMax = 0;
8932 ret->err = NULL;
8933 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008934 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00008935 ret->states = NULL;
8936 ret->freeState = NULL;
8937 ret->freeStates = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008938 return (ret);
8939}
8940
8941/**
8942 * xmlRelaxNGFreeValidCtxt:
8943 * @ctxt: the schema validation context
8944 *
8945 * Free the resources associated to the schema validation context
8946 */
8947void
8948xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008949 int k;
8950
Daniel Veillard6eadf632003-01-23 18:29:16 +00008951 if (ctxt == NULL)
8952 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008953 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008954 xmlRelaxNGFreeStates(NULL, ctxt->states);
8955 if (ctxt->freeState != NULL) {
8956 for (k = 0;k < ctxt->freeState->nbState;k++) {
8957 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
8958 }
8959 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
8960 }
Daniel Veillard798024a2003-03-19 10:36:09 +00008961 if (ctxt->freeStates != NULL) {
8962 for (k = 0;k < ctxt->freeStatesNr;k++) {
8963 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
8964 }
8965 xmlFree(ctxt->freeStates);
8966 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00008967 if (ctxt->errTab != NULL)
8968 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008969 xmlFree(ctxt);
8970}
8971
8972/**
8973 * xmlRelaxNGSetValidErrors:
8974 * @ctxt: a Relax-NG validation context
8975 * @err: the error function
8976 * @warn: the warning function
8977 * @ctx: the functions context
8978 *
8979 * Set the error and warning callback informations
8980 */
8981void
8982xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8983 xmlRelaxNGValidityErrorFunc err,
8984 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8985 if (ctxt == NULL)
8986 return;
8987 ctxt->error = err;
8988 ctxt->warning = warn;
8989 ctxt->userData = ctx;
8990}
8991
8992/**
8993 * xmlRelaxNGValidateDoc:
8994 * @ctxt: a Relax-NG validation context
8995 * @doc: a parsed document tree
8996 *
8997 * Validate a document tree in memory.
8998 *
8999 * Returns 0 if the document is valid, a positive error code
9000 * number otherwise and -1 in case of internal or API error.
9001 */
9002int
9003xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9004 int ret;
9005
9006 if ((ctxt == NULL) || (doc == NULL))
9007 return(-1);
9008
9009 ctxt->doc = doc;
9010
9011 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00009012 /*
9013 * TODO: build error codes
9014 */
9015 if (ret == -1)
9016 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009017 return(ret);
9018}
9019
9020#endif /* LIBXML_SCHEMAS_ENABLED */
9021