blob: 67423e9106ed31d528c991631843cbc2f4ed14f7 [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 Veillard1564e6e2003-03-15 21:30:25 +0000134
Daniel Veillard6eadf632003-01-23 18:29:16 +0000135struct _xmlRelaxNGDefine {
136 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000137 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000138 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000139 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000140 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000141 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000142 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000143 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000144 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000145 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000146 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000147 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000148 short depth; /* used for the cycle detection */
149 short flags; /* define related flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000150};
151
152/**
153 * _xmlRelaxNG:
154 *
155 * A RelaxNGs definition
156 */
157struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000158 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000159 xmlRelaxNGGrammarPtr topgrammar;
160 xmlDocPtr doc;
161
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000162 int idref; /* requires idref checking */
163
Daniel Veillard6eadf632003-01-23 18:29:16 +0000164 xmlHashTablePtr defs; /* define */
165 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000166 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
167 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000168 int defNr; /* number of defines used */
169 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000170
Daniel Veillard6eadf632003-01-23 18:29:16 +0000171};
172
Daniel Veillard77648bb2003-02-20 15:03:22 +0000173#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
174#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
175#define XML_RELAXNG_IN_LIST (1 << 2)
176#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
177#define XML_RELAXNG_IN_START (1 << 4)
178#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
179#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
180#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000181#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
182#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000183
184struct _xmlRelaxNGParserCtxt {
185 void *userData; /* user specific data block */
186 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
187 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000188 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000189
190 xmlRelaxNGPtr schema; /* The schema in use */
191 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000192 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000193 int flags; /* parser flags */
194 int nbErrors; /* number of errors at parse time */
195 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000196 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000197 xmlRelaxNGDefinePtr def; /* the current define */
198
199 int nbInterleaves;
200 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000201
Daniel Veillardc482e262003-02-26 14:48:48 +0000202 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
203 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000204 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000205 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000206
Daniel Veillard419a7682003-02-03 23:22:49 +0000207 int defNr; /* number of defines used */
208 int defMax; /* number of defines aloocated */
209 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
210
Daniel Veillard6eadf632003-01-23 18:29:16 +0000211 const char *buffer;
212 int size;
213
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000214 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000215 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000216 int docNr; /* Depth of the parsing stack */
217 int docMax; /* Max depth of the parsing stack */
218 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000219
220 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000221 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000222 int incNr; /* Depth of the include parsing stack */
223 int incMax; /* Max depth of the parsing stack */
224 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000225
226 int idref; /* requires idref checking */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000227};
228
229#define FLAGS_IGNORABLE 1
230#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000231#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000232
233/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000234 * xmlRelaxNGInterleaveGroup:
235 *
236 * A RelaxNGs partition set associated to lists of definitions
237 */
238typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
239typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
240struct _xmlRelaxNGInterleaveGroup {
241 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
242 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000243 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000244};
245
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000246#define IS_DETERMINIST 1
247#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000248/**
249 * xmlRelaxNGPartitions:
250 *
251 * A RelaxNGs partition associated to an interleave group
252 */
253typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
254typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
255struct _xmlRelaxNGPartition {
256 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000257 xmlHashTablePtr triage; /* hash table used to direct nodes to the
258 right group when possible */
259 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000260 xmlRelaxNGInterleaveGroupPtr *groups;
261};
262
263/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000264 * xmlRelaxNGValidState:
265 *
266 * A RelaxNGs validation state
267 */
268#define MAX_ATTR 20
269typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
270typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
271struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000272 xmlNodePtr node; /* the current node */
273 xmlNodePtr seq; /* the sequence of children left to validate */
274 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000275 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000276 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000277 xmlChar *value; /* the value when operating on string */
278 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000279 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000280};
281
282/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000283 * xmlRelaxNGStates:
284 *
285 * A RelaxNGs container for validation state
286 */
287typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
288typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
289struct _xmlRelaxNGStates {
290 int nbState; /* the number of states */
291 int maxState; /* the size of the array */
292 xmlRelaxNGValidStatePtr *tabState;
293};
294
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000295#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000296/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000297 * xmlRelaxNGValidError:
298 *
299 * A RelaxNGs validation error
300 */
301typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
302typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
303struct _xmlRelaxNGValidError {
304 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000305 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000306 xmlNodePtr node; /* the current node */
307 xmlNodePtr seq; /* the current child */
308 const xmlChar * arg1; /* first arg */
309 const xmlChar * arg2; /* second arg */
310};
311
312/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000313 * xmlRelaxNGValidCtxt:
314 *
315 * A RelaxNGs validation context
316 */
317
318struct _xmlRelaxNGValidCtxt {
319 void *userData; /* user specific data block */
320 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
321 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
322
323 xmlRelaxNGPtr schema; /* The schema in use */
324 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000325 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000326 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000327 int idref; /* requires idref checking */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000328
329 /*
330 * Errors accumulated in branches may have to be stacked to be
331 * provided back when it's sure they affect validation.
332 */
333 xmlRelaxNGValidErrorPtr err; /* Last error */
334 int errNr; /* Depth of the error stack */
335 int errMax; /* Max depth of the error stack */
336 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000337
Daniel Veillardfd573f12003-03-16 17:52:32 +0000338 xmlRelaxNGValidStatePtr state; /* the current validation state */
339 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000340
341 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
342 int freeStatesNr;
343 int freeStatesMax;
344 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000345};
346
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000347/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000348 * xmlRelaxNGInclude:
349 *
350 * Structure associated to a RelaxNGs document element
351 */
352struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000353 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000354 xmlChar *href; /* the normalized href value */
355 xmlDocPtr doc; /* the associated XML document */
356 xmlRelaxNGDefinePtr content;/* the definitions */
357 xmlRelaxNGPtr schema; /* the schema */
358};
359
360/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000361 * xmlRelaxNGDocument:
362 *
363 * Structure associated to a RelaxNGs document element
364 */
365struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000366 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000367 xmlChar *href; /* the normalized href value */
368 xmlDocPtr doc; /* the associated XML document */
369 xmlRelaxNGDefinePtr content;/* the definitions */
370 xmlRelaxNGPtr schema; /* the schema */
371};
372
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000373
Daniel Veillard6eadf632003-01-23 18:29:16 +0000374/************************************************************************
375 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000376 * Preliminary type checking interfaces *
377 * *
378 ************************************************************************/
379/**
380 * xmlRelaxNGTypeHave:
381 * @data: data needed for the library
382 * @type: the type name
383 * @value: the value to check
384 *
385 * Function provided by a type library to check if a type is exported
386 *
387 * Returns 1 if yes, 0 if no and -1 in case of error.
388 */
389typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
390
391/**
392 * xmlRelaxNGTypeCheck:
393 * @data: data needed for the library
394 * @type: the type name
395 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000396 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000397 *
398 * Function provided by a type library to check if a value match a type
399 *
400 * Returns 1 if yes, 0 if no and -1 in case of error.
401 */
402typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000403 const xmlChar *value, void **result,
404 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000405
406/**
407 * xmlRelaxNGFacetCheck:
408 * @data: data needed for the library
409 * @type: the type name
410 * @facet: the facet name
411 * @val: the facet value
412 * @strval: the string value
413 * @value: the value to check
414 *
415 * Function provided by a type library to check a value facet
416 *
417 * Returns 1 if yes, 0 if no and -1 in case of error.
418 */
419typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
420 const xmlChar *facet, const xmlChar *val,
421 const xmlChar *strval, void *value);
422
423/**
424 * xmlRelaxNGTypeFree:
425 * @data: data needed for the library
426 * @result: the value to free
427 *
428 * Function provided by a type library to free a returned result
429 */
430typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000431
432/**
433 * xmlRelaxNGTypeCompare:
434 * @data: data needed for the library
435 * @type: the type name
436 * @value1: the first value
437 * @value2: the second value
438 *
439 * Function provided by a type library to compare two values accordingly
440 * to a type.
441 *
442 * Returns 1 if yes, 0 if no and -1 in case of error.
443 */
444typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
445 const xmlChar *value1,
446 const xmlChar *value2);
447typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
448typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
449struct _xmlRelaxNGTypeLibrary {
450 const xmlChar *namespace; /* the datatypeLibrary value */
451 void *data; /* data needed for the library */
452 xmlRelaxNGTypeHave have; /* the export function */
453 xmlRelaxNGTypeCheck check; /* the checking function */
454 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000455 xmlRelaxNGFacetCheck facet; /* the facet check function */
456 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000457};
458
459/************************************************************************
460 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000461 * Allocation functions *
462 * *
463 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000464static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
465static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000466static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000467static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000468static int xmlRelaxNGEqualValidState(
469 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
470 xmlRelaxNGValidStatePtr state1,
471 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000472static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
473 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000474
475/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000476 * xmlRelaxNGFreeDocument:
477 * @docu: a document structure
478 *
479 * Deallocate a RelaxNG document structure.
480 */
481static void
482xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
483{
484 if (docu == NULL)
485 return;
486
487 if (docu->href != NULL)
488 xmlFree(docu->href);
489 if (docu->doc != NULL)
490 xmlFreeDoc(docu->doc);
491 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000492 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000493 xmlFree(docu);
494}
495
496/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000497 * xmlRelaxNGFreeDocumentList:
498 * @docu: a list of document structure
499 *
500 * Deallocate a RelaxNG document structures.
501 */
502static void
503xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
504{
505 xmlRelaxNGDocumentPtr next;
506 while (docu != NULL) {
507 next = docu->next;
508 xmlRelaxNGFreeDocument(docu);
509 docu = next;
510 }
511}
512
513/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000514 * xmlRelaxNGFreeInclude:
515 * @incl: a include structure
516 *
517 * Deallocate a RelaxNG include structure.
518 */
519static void
520xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
521{
522 if (incl == NULL)
523 return;
524
525 if (incl->href != NULL)
526 xmlFree(incl->href);
527 if (incl->doc != NULL)
528 xmlFreeDoc(incl->doc);
529 if (incl->schema != NULL)
530 xmlRelaxNGFree(incl->schema);
531 xmlFree(incl);
532}
533
534/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000535 * xmlRelaxNGFreeIncludeList:
536 * @incl: a include structure list
537 *
538 * Deallocate a RelaxNG include structure.
539 */
540static void
541xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
542{
543 xmlRelaxNGIncludePtr next;
544 while (incl != NULL) {
545 next = incl->next;
546 xmlRelaxNGFreeInclude(incl);
547 incl = next;
548 }
549}
550
551/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000552 * xmlRelaxNGNewRelaxNG:
553 * @ctxt: a Relax-NG validation context (optional)
554 *
555 * Allocate a new RelaxNG structure.
556 *
557 * Returns the newly allocated structure or NULL in case or error
558 */
559static xmlRelaxNGPtr
560xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
561{
562 xmlRelaxNGPtr ret;
563
564 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
565 if (ret == NULL) {
566 if ((ctxt != NULL) && (ctxt->error != NULL))
567 ctxt->error(ctxt->userData, "Out of memory\n");
568 ctxt->nbErrors++;
569 return (NULL);
570 }
571 memset(ret, 0, sizeof(xmlRelaxNG));
572
573 return (ret);
574}
575
576/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000577 * xmlRelaxNGFreeInnerSchema:
578 * @schema: a schema structure
579 *
580 * Deallocate a RelaxNG schema structure.
581 */
582static void
583xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
584{
585 if (schema == NULL)
586 return;
587
588 if (schema->doc != NULL)
589 xmlFreeDoc(schema->doc);
590 if (schema->defTab != NULL) {
591 int i;
592
593 for (i = 0;i < schema->defNr;i++)
594 xmlRelaxNGFreeDefine(schema->defTab[i]);
595 xmlFree(schema->defTab);
596 }
597
598 xmlFree(schema);
599}
600
601/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000602 * xmlRelaxNGFree:
603 * @schema: a schema structure
604 *
605 * Deallocate a RelaxNG structure.
606 */
607void
608xmlRelaxNGFree(xmlRelaxNGPtr schema)
609{
610 if (schema == NULL)
611 return;
612
Daniel Veillard6eadf632003-01-23 18:29:16 +0000613 if (schema->topgrammar != NULL)
614 xmlRelaxNGFreeGrammar(schema->topgrammar);
615 if (schema->doc != NULL)
616 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000617 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000618 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000619 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000620 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000621 if (schema->defTab != NULL) {
622 int i;
623
624 for (i = 0;i < schema->defNr;i++)
625 xmlRelaxNGFreeDefine(schema->defTab[i]);
626 xmlFree(schema->defTab);
627 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000628
629 xmlFree(schema);
630}
631
632/**
633 * xmlRelaxNGNewGrammar:
634 * @ctxt: a Relax-NG validation context (optional)
635 *
636 * Allocate a new RelaxNG grammar.
637 *
638 * Returns the newly allocated structure or NULL in case or error
639 */
640static xmlRelaxNGGrammarPtr
641xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
642{
643 xmlRelaxNGGrammarPtr ret;
644
645 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
646 if (ret == NULL) {
647 if ((ctxt != NULL) && (ctxt->error != NULL))
648 ctxt->error(ctxt->userData, "Out of memory\n");
649 ctxt->nbErrors++;
650 return (NULL);
651 }
652 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
653
654 return (ret);
655}
656
657/**
658 * xmlRelaxNGFreeGrammar:
659 * @grammar: a grammar structure
660 *
661 * Deallocate a RelaxNG grammar structure.
662 */
663static void
664xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
665{
666 if (grammar == NULL)
667 return;
668
Daniel Veillardc482e262003-02-26 14:48:48 +0000669 if (grammar->children != NULL) {
670 xmlRelaxNGFreeGrammar(grammar->children);
671 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000672 if (grammar->next != NULL) {
673 xmlRelaxNGFreeGrammar(grammar->next);
674 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000675 if (grammar->refs != NULL) {
676 xmlHashFree(grammar->refs, NULL);
677 }
678 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000679 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000680 }
681
682 xmlFree(grammar);
683}
684
685/**
686 * xmlRelaxNGNewDefine:
687 * @ctxt: a Relax-NG validation context
688 * @node: the node in the input document.
689 *
690 * Allocate a new RelaxNG define.
691 *
692 * Returns the newly allocated structure or NULL in case or error
693 */
694static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000695xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000696{
697 xmlRelaxNGDefinePtr ret;
698
Daniel Veillard419a7682003-02-03 23:22:49 +0000699 if (ctxt->defMax == 0) {
700 ctxt->defMax = 16;
701 ctxt->defNr = 0;
702 ctxt->defTab = (xmlRelaxNGDefinePtr *)
703 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
704 if (ctxt->defTab == NULL) {
705 if ((ctxt != NULL) && (ctxt->error != NULL))
706 ctxt->error(ctxt->userData, "Out of memory\n");
707 ctxt->nbErrors++;
708 return (NULL);
709 }
710 } else if (ctxt->defMax <= ctxt->defNr) {
711 xmlRelaxNGDefinePtr *tmp;
712 ctxt->defMax *= 2;
713 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
714 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
715 if (tmp == NULL) {
716 if ((ctxt != NULL) && (ctxt->error != NULL))
717 ctxt->error(ctxt->userData, "Out of memory\n");
718 ctxt->nbErrors++;
719 return (NULL);
720 }
721 ctxt->defTab = tmp;
722 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000723 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
724 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000725 if ((ctxt != NULL) && (ctxt->error != NULL))
726 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000727 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000728 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000729 }
730 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000731 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000732 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000733 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000734 return (ret);
735}
736
737/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000738 * xmlRelaxNGFreePartition:
739 * @partitions: a partition set structure
740 *
741 * Deallocate RelaxNG partition set structures.
742 */
743static void
744xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
745 xmlRelaxNGInterleaveGroupPtr group;
746 int j;
747
748 if (partitions != NULL) {
749 if (partitions->groups != NULL) {
750 for (j = 0;j < partitions->nbgroups;j++) {
751 group = partitions->groups[j];
752 if (group != NULL) {
753 if (group->defs != NULL)
754 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000755 if (group->attrs != NULL)
756 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000757 xmlFree(group);
758 }
759 }
760 xmlFree(partitions->groups);
761 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000762 if (partitions->triage != NULL) {
763 xmlHashFree(partitions->triage, NULL);
764 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000765 xmlFree(partitions);
766 }
767}
768/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000769 * xmlRelaxNGFreeDefine:
770 * @define: a define structure
771 *
772 * Deallocate a RelaxNG define structure.
773 */
774static void
775xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
776{
777 if (define == NULL)
778 return;
779
Daniel Veillard419a7682003-02-03 23:22:49 +0000780 if ((define->data != NULL) &&
781 (define->type == XML_RELAXNG_INTERLEAVE))
782 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000783 if (define->name != NULL)
784 xmlFree(define->name);
785 if (define->ns != NULL)
786 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000787 if (define->value != NULL)
788 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000789 xmlFree(define);
790}
791
792/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000793 * xmlRelaxNGNewStates:
794 * @ctxt: a Relax-NG validation context
795 * @size: the default size for the container
796 *
797 * Allocate a new RelaxNG validation state container
798 * TODO: keep a pool in the ctxt
799 *
800 * Returns the newly allocated structure or NULL in case or error
801 */
802static xmlRelaxNGStatesPtr
803xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
804{
805 xmlRelaxNGStatesPtr ret;
806
Daniel Veillard798024a2003-03-19 10:36:09 +0000807 if ((ctxt != NULL) &&
808 (ctxt->freeState != NULL) &&
809 (ctxt->freeStatesNr > 0)) {
810 ctxt->freeStatesNr--;
811 ret = ctxt->freeStates[ctxt->freeStatesNr];
812 ret->nbState = 0;
813 return(ret);
814 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000815 if (size < 16) size = 16;
816
817 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
818 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
819 if (ret == NULL) {
820 if ((ctxt != NULL) && (ctxt->error != NULL))
821 ctxt->error(ctxt->userData, "Out of memory\n");
822 return (NULL);
823 }
824 ret->nbState = 0;
825 ret->maxState = size;
826 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
827 (size) * sizeof(xmlRelaxNGValidStatePtr));
828 if (ret->tabState == NULL) {
829 if ((ctxt != NULL) && (ctxt->error != NULL))
830 ctxt->error(ctxt->userData, "Out of memory\n");
831 xmlFree(ret->tabState);
832 return (NULL);
833 }
834 return(ret);
835}
836
837/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000838 * xmlRelaxNGAddStateUniq:
839 * @ctxt: a Relax-NG validation context
840 * @states: the states container
841 * @state: the validation state
842 *
843 * Add a RelaxNG validation state to the container without checking
844 * for unicity.
845 *
846 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
847 */
848static int
849xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
850 xmlRelaxNGStatesPtr states,
851 xmlRelaxNGValidStatePtr state)
852{
853 if (state == NULL) {
854 return(-1);
855 }
856 if (states->nbState >= states->maxState) {
857 xmlRelaxNGValidStatePtr *tmp;
858 int size;
859
860 size = states->maxState * 2;
861 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
862 (size) * sizeof(xmlRelaxNGValidStatePtr));
863 if (tmp == NULL) {
864 if ((ctxt != NULL) && (ctxt->error != NULL))
865 ctxt->error(ctxt->userData, "Out of memory\n");
866 return(-1);
867 }
868 states->tabState = tmp;
869 states->maxState = size;
870 }
871 states->tabState[states->nbState++] = state;
872 return(1);
873}
874
875/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000876 * xmlRelaxNGAddState:
877 * @ctxt: a Relax-NG validation context
878 * @states: the states container
879 * @state: the validation state
880 *
881 * Add a RelaxNG validation state to the container
882 *
883 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
884 */
885static int
886xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
887 xmlRelaxNGValidStatePtr state)
888{
889 int i;
890
891 if (state == NULL) {
892 return(-1);
893 }
894 if (states->nbState >= states->maxState) {
895 xmlRelaxNGValidStatePtr *tmp;
896 int size;
897
898 size = states->maxState * 2;
899 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
900 (size) * sizeof(xmlRelaxNGValidStatePtr));
901 if (tmp == NULL) {
902 if ((ctxt != NULL) && (ctxt->error != NULL))
903 ctxt->error(ctxt->userData, "Out of memory\n");
904 return(-1);
905 }
906 states->tabState = tmp;
907 states->maxState = size;
908 }
909 for (i = 0;i < states->nbState;i++) {
910 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000911 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000912 return(0);
913 }
914 }
915 states->tabState[states->nbState++] = state;
916 return(1);
917}
918
919/**
920 * xmlRelaxNGFreeStates:
921 * @ctxt: a Relax-NG validation context
922 * @states: teh container
923 *
924 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000925 */
926static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000927xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000928 xmlRelaxNGStatesPtr states)
929{
Daniel Veillard798024a2003-03-19 10:36:09 +0000930 if (states == NULL)
931 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000932 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
933 ctxt->freeStatesMax = 40;
934 ctxt->freeStatesNr = 0;
935 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
936 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
937 if (ctxt->freeStates == NULL) {
938 if ((ctxt != NULL) && (ctxt->error != NULL))
939 ctxt->error(ctxt->userData, "Out of memory\n");
940 }
941 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
942 xmlRelaxNGStatesPtr *tmp;
943
944 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
945 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
946 if (tmp == NULL) {
947 if ((ctxt != NULL) && (ctxt->error != NULL))
948 ctxt->error(ctxt->userData, "Out of memory\n");
949 xmlFree(states->tabState);
950 xmlFree(states);
951 return;
952 }
953 ctxt->freeStates = tmp;
954 ctxt->freeStatesMax *= 2;
955 }
956 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000957 xmlFree(states->tabState);
958 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000959 } else {
960 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000961 }
962}
963
964/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000965 * xmlRelaxNGNewValidState:
966 * @ctxt: a Relax-NG validation context
967 * @node: the current node or NULL for the document
968 *
969 * Allocate a new RelaxNG validation state
970 *
971 * Returns the newly allocated structure or NULL in case or error
972 */
973static xmlRelaxNGValidStatePtr
974xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
975{
976 xmlRelaxNGValidStatePtr ret;
977 xmlAttrPtr attr;
978 xmlAttrPtr attrs[MAX_ATTR];
979 int nbAttrs = 0;
980 xmlNodePtr root = NULL;
981
982 if (node == NULL) {
983 root = xmlDocGetRootElement(ctxt->doc);
984 if (root == NULL)
985 return(NULL);
986 } else {
987 attr = node->properties;
988 while (attr != NULL) {
989 if (nbAttrs < MAX_ATTR)
990 attrs[nbAttrs++] = attr;
991 else
992 nbAttrs++;
993 attr = attr->next;
994 }
995 }
Daniel Veillard798024a2003-03-19 10:36:09 +0000996 if ((ctxt->freeState != NULL) &&
997 (ctxt->freeState->nbState > 0)) {
998 ctxt->freeState->nbState--;
999 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1000 } else {
1001 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1002 if (ret == NULL) {
1003 if ((ctxt != NULL) && (ctxt->error != NULL))
1004 ctxt->error(ctxt->userData, "Out of memory\n");
1005 return (NULL);
1006 }
1007 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001008 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001009 ret->value = NULL;
1010 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001011 if (node == NULL) {
1012 ret->node = (xmlNodePtr) ctxt->doc;
1013 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001014 } else {
1015 ret->node = node;
1016 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001017 }
1018 ret->nbAttrs = 0;
1019 if (nbAttrs > 0) {
1020 if (ret->attrs == NULL) {
1021 if (nbAttrs < 4) ret->maxAttrs = 4;
1022 else ret->maxAttrs = nbAttrs;
1023 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1024 sizeof(xmlAttrPtr));
1025 if (ret->attrs == NULL) {
1026 if ((ctxt != NULL) && (ctxt->error != NULL))
1027 ctxt->error(ctxt->userData, "Out of memory\n");
1028 return (ret);
1029 }
1030 } else if (ret->maxAttrs < nbAttrs) {
1031 xmlAttrPtr *tmp;
1032
1033 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1034 sizeof(xmlAttrPtr));
1035 if (tmp == NULL) {
1036 if ((ctxt != NULL) && (ctxt->error != NULL))
1037 ctxt->error(ctxt->userData, "Out of memory\n");
1038 return (ret);
1039 }
1040 ret->attrs = tmp;
1041 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001042 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001043 if (nbAttrs < MAX_ATTR) {
1044 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1045 } else {
1046 attr = node->properties;
1047 nbAttrs = 0;
1048 while (attr != NULL) {
1049 ret->attrs[nbAttrs++] = attr;
1050 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001051 }
1052 }
1053 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001054 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001055 if (ret->node == NULL) {
1056 printf("pbm!\n");
1057 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001058 return (ret);
1059}
1060
1061/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001062 * xmlRelaxNGCopyValidState:
1063 * @ctxt: a Relax-NG validation context
1064 * @state: a validation state
1065 *
1066 * Copy the validation state
1067 *
1068 * Returns the newly allocated structure or NULL in case or error
1069 */
1070static xmlRelaxNGValidStatePtr
1071xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1072 xmlRelaxNGValidStatePtr state)
1073{
1074 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001075 unsigned int maxAttrs;
1076 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001077
1078 if (state == NULL)
1079 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001080 if ((ctxt->freeState != NULL) &&
1081 (ctxt->freeState->nbState > 0)) {
1082 ctxt->freeState->nbState--;
1083 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1084 } else {
1085 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1086 if (ret == NULL) {
1087 if ((ctxt != NULL) && (ctxt->error != NULL))
1088 ctxt->error(ctxt->userData, "Out of memory\n");
1089 return (NULL);
1090 }
1091 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001092 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001093 attrs = ret->attrs;
1094 maxAttrs = ret->maxAttrs;
1095 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1096 ret->attrs = attrs;
1097 ret->maxAttrs = maxAttrs;
1098 if (state->nbAttrs > 0) {
1099 if (ret->attrs == NULL) {
1100 ret->maxAttrs = state->maxAttrs;
1101 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1102 sizeof(xmlAttrPtr));
1103 if (ret->attrs == NULL) {
1104 if ((ctxt != NULL) && (ctxt->error != NULL))
1105 ctxt->error(ctxt->userData, "Out of memory\n");
1106 ret->nbAttrs = 0;
1107 return (ret);
1108 }
1109 } else if (ret->maxAttrs < state->nbAttrs) {
1110 xmlAttrPtr *tmp;
1111
1112 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1113 sizeof(xmlAttrPtr));
1114 if (tmp == NULL) {
1115 if ((ctxt != NULL) && (ctxt->error != NULL))
1116 ctxt->error(ctxt->userData, "Out of memory\n");
1117 ret->nbAttrs = 0;
1118 return (ret);
1119 }
1120 ret->maxAttrs = state->maxAttrs;
1121 }
1122 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1123 }
1124 if (ret->node == NULL) {
1125 printf("pbm!\n");
1126 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001127 return(ret);
1128}
1129
1130/**
1131 * xmlRelaxNGEqualValidState:
1132 * @ctxt: a Relax-NG validation context
1133 * @state1: a validation state
1134 * @state2: a validation state
1135 *
1136 * Compare the validation states for equality
1137 *
1138 * Returns 1 if equald, 0 otherwise
1139 */
1140static int
1141xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1142 xmlRelaxNGValidStatePtr state1,
1143 xmlRelaxNGValidStatePtr state2)
1144{
1145 int i;
1146
1147 if ((state1 == NULL) || (state2 == NULL))
1148 return(0);
1149 if (state1 == state2)
1150 return(1);
1151 if (state1->node != state2->node)
1152 return(0);
1153 if (state1->seq != state2->seq)
1154 return(0);
1155 if (state1->nbAttrLeft != state2->nbAttrLeft)
1156 return(0);
1157 if (state1->nbAttrs != state2->nbAttrs)
1158 return(0);
1159 if (state1->endvalue != state2->endvalue)
1160 return(0);
1161 if ((state1->value != state2->value) &&
1162 (!xmlStrEqual(state1->value, state2->value)))
1163 return(0);
1164 for (i = 0;i < state1->nbAttrs;i++) {
1165 if (state1->attrs[i] != state2->attrs[i])
1166 return(0);
1167 }
1168 return(1);
1169}
1170
1171/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001172 * xmlRelaxNGFreeValidState:
1173 * @state: a validation state structure
1174 *
1175 * Deallocate a RelaxNG validation state structure.
1176 */
1177static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001178xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1179 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001180{
1181 if (state == NULL)
1182 return;
1183
Daniel Veillard798024a2003-03-19 10:36:09 +00001184 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1185 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1186 }
1187 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1188 if (state->attrs != NULL)
1189 xmlFree(state->attrs);
1190 xmlFree(state);
1191 } else {
1192 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1193 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001194}
1195
1196/************************************************************************
1197 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001198 * Document functions *
1199 * *
1200 ************************************************************************/
1201static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1202 xmlDocPtr doc);
1203
1204/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001205 * xmlRelaxNGIncludePush:
1206 * @ctxt: the parser context
1207 * @value: the element doc
1208 *
1209 * Pushes a new include on top of the include stack
1210 *
1211 * Returns 0 in case of error, the index in the stack otherwise
1212 */
1213static int
1214xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1215 xmlRelaxNGIncludePtr value)
1216{
1217 if (ctxt->incTab == NULL) {
1218 ctxt->incMax = 4;
1219 ctxt->incNr = 0;
1220 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1221 ctxt->incMax * sizeof(ctxt->incTab[0]));
1222 if (ctxt->incTab == NULL) {
1223 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1224 return (0);
1225 }
1226 }
1227 if (ctxt->incNr >= ctxt->incMax) {
1228 ctxt->incMax *= 2;
1229 ctxt->incTab =
1230 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1231 ctxt->incMax *
1232 sizeof(ctxt->incTab[0]));
1233 if (ctxt->incTab == NULL) {
1234 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1235 return (0);
1236 }
1237 }
1238 ctxt->incTab[ctxt->incNr] = value;
1239 ctxt->inc = value;
1240 return (ctxt->incNr++);
1241}
1242
1243/**
1244 * xmlRelaxNGIncludePop:
1245 * @ctxt: the parser context
1246 *
1247 * Pops the top include from the include stack
1248 *
1249 * Returns the include just removed
1250 */
1251static xmlRelaxNGIncludePtr
1252xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1253{
1254 xmlRelaxNGIncludePtr ret;
1255
1256 if (ctxt->incNr <= 0)
1257 return (0);
1258 ctxt->incNr--;
1259 if (ctxt->incNr > 0)
1260 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1261 else
1262 ctxt->inc = NULL;
1263 ret = ctxt->incTab[ctxt->incNr];
1264 ctxt->incTab[ctxt->incNr] = 0;
1265 return (ret);
1266}
1267
1268/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001269 * xmlRelaxNGRemoveRedefine:
1270 * @ctxt: the parser context
1271 * @URL: the normalized URL
1272 * @target: the included target
1273 * @name: the define name to eliminate
1274 *
1275 * Applies the elimination algorithm of 4.7
1276 *
1277 * Returns 0 in case of error, 1 in case of success.
1278 */
1279static int
1280xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1281 const xmlChar *URL ATTRIBUTE_UNUSED,
1282 xmlNodePtr target, const xmlChar *name) {
1283 int found = 0;
1284 xmlNodePtr tmp, tmp2;
1285 xmlChar *name2;
1286
1287#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001288 if (name == NULL)
1289 xmlGenericError(xmlGenericErrorContext,
1290 "Elimination of <include> start from %s\n", URL);
1291 else
1292 xmlGenericError(xmlGenericErrorContext,
1293 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001294#endif
1295 tmp = target;
1296 while (tmp != NULL) {
1297 tmp2 = tmp->next;
1298 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1299 found = 1;
1300 xmlUnlinkNode(tmp);
1301 xmlFreeNode(tmp);
1302 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1303 name2 = xmlGetProp(tmp, BAD_CAST "name");
1304 xmlRelaxNGNormExtSpace(name2);
1305 if (name2 != NULL) {
1306 if (xmlStrEqual(name, name2)) {
1307 found = 1;
1308 xmlUnlinkNode(tmp);
1309 xmlFreeNode(tmp);
1310 }
1311 xmlFree(name2);
1312 }
1313 } else if (IS_RELAXNG(tmp, "include")) {
1314 xmlChar *href = NULL;
1315 xmlRelaxNGDocumentPtr inc = tmp->_private;
1316
1317 if ((inc != NULL) && (inc->doc != NULL) &&
1318 (inc->doc->children != NULL)) {
1319
1320 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1321#ifdef DEBUG_INCLUDE
1322 href = xmlGetProp(tmp, BAD_CAST "href");
1323#endif
1324 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1325 inc->doc->children->children, name) == 1) {
1326 found = 1;
1327 }
1328 if (href != NULL)
1329 xmlFree(href);
1330 }
1331 }
1332 }
1333 tmp = tmp2;
1334 }
1335 return(found);
1336}
1337
1338/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001339 * xmlRelaxNGLoadInclude:
1340 * @ctxt: the parser context
1341 * @URL: the normalized URL
1342 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001343 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001344 *
1345 * First lookup if the document is already loaded into the parser context,
1346 * check against recursion. If not found the resource is loaded and
1347 * the content is preprocessed before being returned back to the caller.
1348 *
1349 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1350 */
1351static xmlRelaxNGIncludePtr
1352xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001353 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001354 xmlRelaxNGIncludePtr ret = NULL;
1355 xmlDocPtr doc;
1356 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001357 xmlNodePtr root, cur;
1358
1359#ifdef DEBUG_INCLUDE
1360 xmlGenericError(xmlGenericErrorContext,
1361 "xmlRelaxNGLoadInclude(%s)\n", URL);
1362#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001363
1364 /*
1365 * check against recursion in the stack
1366 */
1367 for (i = 0;i < ctxt->incNr;i++) {
1368 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1369 if (ctxt->error != NULL)
1370 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001371 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001372 URL);
1373 ctxt->nbErrors++;
1374 return(NULL);
1375 }
1376 }
1377
1378 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001379 * load the document
1380 */
1381 doc = xmlParseFile((const char *) URL);
1382 if (doc == NULL) {
1383 if (ctxt->error != NULL)
1384 ctxt->error(ctxt->userData,
1385 "xmlRelaxNG: could not load %s\n", URL);
1386 ctxt->nbErrors++;
1387 return (NULL);
1388 }
1389
Daniel Veillard5add8682003-03-10 13:13:58 +00001390#ifdef DEBUG_INCLUDE
1391 xmlGenericError(xmlGenericErrorContext,
1392 "Parsed %s Okay\n", URL);
1393#endif
1394
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001395 /*
1396 * Allocate the document structures and register it first.
1397 */
1398 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1399 if (ret == NULL) {
1400 if (ctxt->error != NULL)
1401 ctxt->error(ctxt->userData,
1402 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1403 ctxt->nbErrors++;
1404 xmlFreeDoc(doc);
1405 return (NULL);
1406 }
1407 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1408 ret->doc = doc;
1409 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001410 ret->next = ctxt->includes;
1411 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001412
1413 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001414 * transmit the ns if needed
1415 */
1416 if (ns != NULL) {
1417 root = xmlDocGetRootElement(doc);
1418 if (root != NULL) {
1419 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1420 xmlSetProp(root, BAD_CAST"ns", ns);
1421 }
1422 }
1423 }
1424
1425 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001426 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001428 xmlRelaxNGIncludePush(ctxt, ret);
1429
1430 /*
1431 * Some preprocessing of the document content, this include recursing
1432 * in the include stack.
1433 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001434#ifdef DEBUG_INCLUDE
1435 xmlGenericError(xmlGenericErrorContext,
1436 "cleanup of %s\n", URL);
1437#endif
1438
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001439 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1440 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001441 ctxt->inc = NULL;
1442 return(NULL);
1443 }
1444
1445 /*
1446 * Pop up the include from the stack
1447 */
1448 xmlRelaxNGIncludePop(ctxt);
1449
Daniel Veillard5add8682003-03-10 13:13:58 +00001450#ifdef DEBUG_INCLUDE
1451 xmlGenericError(xmlGenericErrorContext,
1452 "Checking of %s\n", URL);
1453#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001454 /*
1455 * Check that the top element is a grammar
1456 */
1457 root = xmlDocGetRootElement(doc);
1458 if (root == NULL) {
1459 if (ctxt->error != NULL)
1460 ctxt->error(ctxt->userData,
1461 "xmlRelaxNG: included document is empty %s\n", URL);
1462 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001463 return (NULL);
1464 }
1465 if (!IS_RELAXNG(root, "grammar")) {
1466 if (ctxt->error != NULL)
1467 ctxt->error(ctxt->userData,
1468 "xmlRelaxNG: included document %s root is not a grammar\n",
1469 URL);
1470 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001471 return (NULL);
1472 }
1473
1474 /*
1475 * Elimination of redefined rules in the include.
1476 */
1477 cur = node->children;
1478 while (cur != NULL) {
1479 if (IS_RELAXNG(cur, "start")) {
1480 int found = 0;
1481
Daniel Veillard5add8682003-03-10 13:13:58 +00001482 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001483 if (!found) {
1484 if (ctxt->error != NULL)
1485 ctxt->error(ctxt->userData,
1486 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1487 URL);
1488 ctxt->nbErrors++;
1489 }
1490 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001491 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001492
1493 name = xmlGetProp(cur, BAD_CAST "name");
1494 if (name == NULL) {
1495 if (ctxt->error != NULL)
1496 ctxt->error(ctxt->userData,
1497 "xmlRelaxNG: include %s has define without name\n",
1498 URL);
1499 ctxt->nbErrors++;
1500 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001501 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001502
Daniel Veillardd2298792003-02-14 16:54:11 +00001503 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001504 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1505 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001506 if (!found) {
1507 if (ctxt->error != NULL)
1508 ctxt->error(ctxt->userData,
1509 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1510 URL, name);
1511 ctxt->nbErrors++;
1512 }
1513 xmlFree(name);
1514 }
1515 }
1516 cur = cur->next;
1517 }
1518
1519
1520 return(ret);
1521}
1522
1523/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001524 * xmlRelaxNGValidErrorPush:
1525 * @ctxt: the validation context
1526 * @err: the error code
1527 * @arg1: the first string argument
1528 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001529 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001530 *
1531 * Pushes a new error on top of the error stack
1532 *
1533 * Returns 0 in case of error, the index in the stack otherwise
1534 */
1535static int
1536xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001537 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001538{
1539 xmlRelaxNGValidErrorPtr cur;
1540 if (ctxt->errTab == NULL) {
1541 ctxt->errMax = 8;
1542 ctxt->errNr = 0;
1543 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1544 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1545 if (ctxt->errTab == NULL) {
1546 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1547 return (0);
1548 }
1549 }
1550 if (ctxt->errNr >= ctxt->errMax) {
1551 ctxt->errMax *= 2;
1552 ctxt->errTab =
1553 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1554 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1555 if (ctxt->errTab == NULL) {
1556 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1557 return (0);
1558 }
1559 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001560 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001561 (ctxt->err->node == ctxt->state->node) &&
1562 (ctxt->err->err == err))
1563 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001564 cur = &ctxt->errTab[ctxt->errNr];
1565 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001566 if (dup) {
1567 cur->arg1 = xmlStrdup(arg1);
1568 cur->arg2 = xmlStrdup(arg2);
1569 cur->flags = ERROR_IS_DUP;
1570 } else {
1571 cur->arg1 = arg1;
1572 cur->arg2 = arg2;
1573 cur->flags = 0;
1574 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001575 if (ctxt->state != NULL) {
1576 cur->node = ctxt->state->node;
1577 cur->seq = ctxt->state->seq;
1578 } else {
1579 cur->node = NULL;
1580 cur->seq = NULL;
1581 }
1582 ctxt->err = cur;
1583 return (ctxt->errNr++);
1584}
1585
1586/**
1587 * xmlRelaxNGValidErrorPop:
1588 * @ctxt: the validation context
1589 *
1590 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001591 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001592static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001593xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1594{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001595 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001596
1597 if (ctxt->errNr <= 0)
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001598 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001599 ctxt->errNr--;
1600 if (ctxt->errNr > 0)
1601 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1602 else
1603 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001604 cur = &ctxt->errTab[ctxt->errNr];
1605 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001606 if (cur->arg1 != NULL)
1607 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001608 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001609 if (cur->arg2 != NULL)
1610 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001611 cur->arg2 = NULL;
1612 cur->flags = 0;
1613 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001614}
1615
Daniel Veillard42f12e92003-03-07 18:32:59 +00001616/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001617 * xmlRelaxNGDocumentPush:
1618 * @ctxt: the parser context
1619 * @value: the element doc
1620 *
1621 * Pushes a new doc on top of the doc stack
1622 *
1623 * Returns 0 in case of error, the index in the stack otherwise
1624 */
1625static int
1626xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1627 xmlRelaxNGDocumentPtr value)
1628{
1629 if (ctxt->docTab == NULL) {
1630 ctxt->docMax = 4;
1631 ctxt->docNr = 0;
1632 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1633 ctxt->docMax * sizeof(ctxt->docTab[0]));
1634 if (ctxt->docTab == NULL) {
1635 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1636 return (0);
1637 }
1638 }
1639 if (ctxt->docNr >= ctxt->docMax) {
1640 ctxt->docMax *= 2;
1641 ctxt->docTab =
1642 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1643 ctxt->docMax *
1644 sizeof(ctxt->docTab[0]));
1645 if (ctxt->docTab == NULL) {
1646 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1647 return (0);
1648 }
1649 }
1650 ctxt->docTab[ctxt->docNr] = value;
1651 ctxt->doc = value;
1652 return (ctxt->docNr++);
1653}
1654
1655/**
1656 * xmlRelaxNGDocumentPop:
1657 * @ctxt: the parser context
1658 *
1659 * Pops the top doc from the doc stack
1660 *
1661 * Returns the doc just removed
1662 */
1663static xmlRelaxNGDocumentPtr
1664xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1665{
1666 xmlRelaxNGDocumentPtr ret;
1667
1668 if (ctxt->docNr <= 0)
1669 return (0);
1670 ctxt->docNr--;
1671 if (ctxt->docNr > 0)
1672 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1673 else
1674 ctxt->doc = NULL;
1675 ret = ctxt->docTab[ctxt->docNr];
1676 ctxt->docTab[ctxt->docNr] = 0;
1677 return (ret);
1678}
1679
1680/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001681 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001682 * @ctxt: the parser context
1683 * @URL: the normalized URL
1684 * @ns: the inherited ns if any
1685 *
1686 * First lookup if the document is already loaded into the parser context,
1687 * check against recursion. If not found the resource is loaded and
1688 * the content is preprocessed before being returned back to the caller.
1689 *
1690 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1691 */
1692static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001693xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001694 const xmlChar *ns) {
1695 xmlRelaxNGDocumentPtr ret = NULL;
1696 xmlDocPtr doc;
1697 xmlNodePtr root;
1698 int i;
1699
1700 /*
1701 * check against recursion in the stack
1702 */
1703 for (i = 0;i < ctxt->docNr;i++) {
1704 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1705 if (ctxt->error != NULL)
1706 ctxt->error(ctxt->userData,
1707 "Detected an externalRef recursion for %s\n",
1708 URL);
1709 ctxt->nbErrors++;
1710 return(NULL);
1711 }
1712 }
1713
1714 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001715 * load the document
1716 */
1717 doc = xmlParseFile((const char *) URL);
1718 if (doc == NULL) {
1719 if (ctxt->error != NULL)
1720 ctxt->error(ctxt->userData,
1721 "xmlRelaxNG: could not load %s\n", URL);
1722 ctxt->nbErrors++;
1723 return (NULL);
1724 }
1725
1726 /*
1727 * Allocate the document structures and register it first.
1728 */
1729 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1730 if (ret == NULL) {
1731 if (ctxt->error != NULL)
1732 ctxt->error(ctxt->userData,
1733 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1734 ctxt->nbErrors++;
1735 xmlFreeDoc(doc);
1736 return (NULL);
1737 }
1738 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1739 ret->doc = doc;
1740 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001741 ret->next = ctxt->documents;
1742 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001743
1744 /*
1745 * transmit the ns if needed
1746 */
1747 if (ns != NULL) {
1748 root = xmlDocGetRootElement(doc);
1749 if (root != NULL) {
1750 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1751 xmlSetProp(root, BAD_CAST"ns", ns);
1752 }
1753 }
1754 }
1755
1756 /*
1757 * push it on the stack and register it in the hash table
1758 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001759 xmlRelaxNGDocumentPush(ctxt, ret);
1760
1761 /*
1762 * Some preprocessing of the document content
1763 */
1764 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1765 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001766 ctxt->doc = NULL;
1767 return(NULL);
1768 }
1769
1770 xmlRelaxNGDocumentPop(ctxt);
1771
1772 return(ret);
1773}
1774
1775/************************************************************************
1776 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001777 * Error functions *
1778 * *
1779 ************************************************************************/
1780
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001781#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1782#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1783#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1784#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1785#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001786
Daniel Veillardfd573f12003-03-16 17:52:32 +00001787#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001788static const char *
1789xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1790 if (def == NULL)
1791 return("none");
1792 switch(def->type) {
1793 case XML_RELAXNG_EMPTY: return("empty");
1794 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1795 case XML_RELAXNG_EXCEPT: return("except");
1796 case XML_RELAXNG_TEXT: return("text");
1797 case XML_RELAXNG_ELEMENT: return("element");
1798 case XML_RELAXNG_DATATYPE: return("datatype");
1799 case XML_RELAXNG_VALUE: return("value");
1800 case XML_RELAXNG_LIST: return("list");
1801 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1802 case XML_RELAXNG_DEF: return("def");
1803 case XML_RELAXNG_REF: return("ref");
1804 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1805 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001806 case XML_RELAXNG_OPTIONAL: return("optional");
1807 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001808 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1809 case XML_RELAXNG_CHOICE: return("choice");
1810 case XML_RELAXNG_GROUP: return("group");
1811 case XML_RELAXNG_INTERLEAVE: return("interleave");
1812 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001813 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001814 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001815 }
1816 return("unknown");
1817}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001818#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001819
Daniel Veillard6eadf632003-01-23 18:29:16 +00001820/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001821 * xmlRelaxNGGetErrorString:
1822 * @err: the error code
1823 * @arg1: the first string argument
1824 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001825 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001826 * computes a formatted error string for the given error code and args
1827 *
1828 * Returns the error string, it must be deallocated by the caller
1829 */
1830static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001831xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1832 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001833 char msg[1000];
1834
1835 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001836 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001837 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001838 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001839
1840 msg[0] = 0;
1841 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001842 case XML_RELAXNG_OK:
1843 return(NULL);
1844 case XML_RELAXNG_ERR_MEMORY:
1845 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001846 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001847 snprintf(msg, 1000, "failed to validate type %s", arg1);
1848 break;
1849 case XML_RELAXNG_ERR_TYPEVAL:
1850 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1851 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001852 case XML_RELAXNG_ERR_DUPID:
1853 snprintf(msg, 1000, "ID %s redefined", arg1);
1854 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001855 case XML_RELAXNG_ERR_TYPECMP:
1856 snprintf(msg, 1000, "failed to compare type %s", arg1);
1857 break;
1858 case XML_RELAXNG_ERR_NOSTATE:
1859 return(xmlCharStrdup("Internal error: no state"));
1860 case XML_RELAXNG_ERR_NODEFINE:
1861 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001862 case XML_RELAXNG_ERR_INTERNAL:
1863 snprintf(msg, 1000, "Internal error: %s", arg1);
1864 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001865 case XML_RELAXNG_ERR_LISTEXTRA:
1866 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1867 break;
1868 case XML_RELAXNG_ERR_INTERNODATA:
1869 return(xmlCharStrdup("Internal: interleave block has no data"));
1870 case XML_RELAXNG_ERR_INTERSEQ:
1871 return(xmlCharStrdup("Invalid sequence in interleave"));
1872 case XML_RELAXNG_ERR_INTEREXTRA:
1873 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1874 break;
1875 case XML_RELAXNG_ERR_ELEMNAME:
1876 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1877 break;
1878 case XML_RELAXNG_ERR_ELEMNONS:
1879 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1880 break;
1881 case XML_RELAXNG_ERR_ELEMWRONGNS:
1882 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1883 arg1, arg2);
1884 break;
1885 case XML_RELAXNG_ERR_ELEMEXTRANS:
1886 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1887 break;
1888 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1889 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1890 break;
1891 case XML_RELAXNG_ERR_NOELEM:
1892 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1893 break;
1894 case XML_RELAXNG_ERR_NOTELEM:
1895 return(xmlCharStrdup("Expecting an element got text"));
1896 case XML_RELAXNG_ERR_ATTRVALID:
1897 snprintf(msg, 1000, "Element %s failed to validate attributes",
1898 arg1);
1899 break;
1900 case XML_RELAXNG_ERR_CONTENTVALID:
1901 snprintf(msg, 1000, "Element %s failed to validate content",
1902 arg1);
1903 break;
1904 case XML_RELAXNG_ERR_EXTRACONTENT:
1905 snprintf(msg, 1000, "Element %s has extra content: %s",
1906 arg1, arg2);
1907 break;
1908 case XML_RELAXNG_ERR_INVALIDATTR:
1909 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1910 arg1, arg2);
1911 break;
1912 case XML_RELAXNG_ERR_DATAELEM:
1913 snprintf(msg, 1000, "Datatype element %s has child elements",
1914 arg1);
1915 break;
1916 case XML_RELAXNG_ERR_VALELEM:
1917 snprintf(msg, 1000, "Value element %s has child elements",
1918 arg1);
1919 break;
1920 case XML_RELAXNG_ERR_LISTELEM:
1921 snprintf(msg, 1000, "List element %s has child elements",
1922 arg1);
1923 break;
1924 case XML_RELAXNG_ERR_DATATYPE:
1925 snprintf(msg, 1000, "Error validating datatype %s",
1926 arg1);
1927 break;
1928 case XML_RELAXNG_ERR_VALUE:
1929 snprintf(msg, 1000, "Error validating value %s",
1930 arg1);
1931 break;
1932 case XML_RELAXNG_ERR_LIST:
1933 return(xmlCharStrdup("Error validating list"));
1934 case XML_RELAXNG_ERR_NOGRAMMAR:
1935 return(xmlCharStrdup("No top grammar defined"));
1936 case XML_RELAXNG_ERR_EXTRADATA:
1937 return(xmlCharStrdup("Extra data in the document"));
1938 default:
1939 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001940 }
1941 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001942 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001943 }
1944 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001945 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001946}
1947
1948/**
1949 * xmlRelaxNGValidErrorContext:
1950 * @ctxt: the validation context
1951 * @node: the node
1952 * @child: the node child generating the problem.
1953 *
1954 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001955 */
1956static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001957xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1958 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001959{
1960 int line = 0;
1961 const xmlChar *file = NULL;
1962 const xmlChar *name = NULL;
1963 const char *type = "error";
1964
1965 if ((ctxt == NULL) || (ctxt->error == NULL))
1966 return;
1967
1968 if (child != NULL)
1969 node = child;
1970
1971 if (node != NULL) {
1972 if ((node->type == XML_DOCUMENT_NODE) ||
1973 (node->type == XML_HTML_DOCUMENT_NODE)) {
1974 xmlDocPtr doc = (xmlDocPtr) node;
1975
1976 file = doc->URL;
1977 } else {
1978 /*
1979 * Try to find contextual informations to report
1980 */
1981 if (node->type == XML_ELEMENT_NODE) {
1982 line = (int) node->content;
1983 } else if ((node->prev != NULL) &&
1984 (node->prev->type == XML_ELEMENT_NODE)) {
1985 line = (int) node->prev->content;
1986 } else if ((node->parent != NULL) &&
1987 (node->parent->type == XML_ELEMENT_NODE)) {
1988 line = (int) node->parent->content;
1989 }
1990 if ((node->doc != NULL) && (node->doc->URL != NULL))
1991 file = node->doc->URL;
1992 if (node->name != NULL)
1993 name = node->name;
1994 }
1995 }
1996
Daniel Veillard42f12e92003-03-07 18:32:59 +00001997 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001998
1999 if ((file != NULL) && (line != 0) && (name != NULL))
2000 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2001 type, file, line, name);
2002 else if ((file != NULL) && (name != NULL))
2003 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2004 type, file, name);
2005 else if ((file != NULL) && (line != 0))
2006 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2007 else if (file != NULL)
2008 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2009 else if (name != NULL)
2010 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2011 else
2012 ctxt->error(ctxt->userData, "%s\n", type);
2013}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002014
2015/**
2016 * xmlRelaxNGShowValidError:
2017 * @ctxt: the validation context
2018 * @err: the error number
2019 * @node: the node
2020 * @child: the node child generating the problem.
2021 * @arg1: the first argument
2022 * @arg2: the second argument
2023 *
2024 * Show a validation error.
2025 */
2026static void
2027xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2028 xmlNodePtr node, xmlNodePtr child,
2029 const xmlChar *arg1, const xmlChar *arg2)
2030{
2031 xmlChar *msg;
2032
2033 if (ctxt->error == NULL)
2034 return;
2035
2036 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2037 if (msg == NULL)
2038 return;
2039
2040 xmlRelaxNGValidErrorContext(ctxt, node, child);
2041 ctxt->error(ctxt->userData, "%s\n", msg);
2042 xmlFree(msg);
2043}
2044
2045/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002046 * xmlRelaxNGPopErrors:
2047 * @ctxt: the validation context
2048 * @level: the error level in the stack
2049 *
2050 * pop and discard all errors until the given level is reached
2051 */
2052static void
2053xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2054 int i;
2055 xmlRelaxNGValidErrorPtr err;
2056
2057 for (i = level;i < ctxt->errNr;i++) {
2058 err = &ctxt->errTab[i];
2059 if (err->flags & ERROR_IS_DUP) {
2060 if (err->arg1 != NULL)
2061 xmlFree((xmlChar *)err->arg1);
2062 err->arg1 = NULL;
2063 if (err->arg2 != NULL)
2064 xmlFree((xmlChar *)err->arg2);
2065 err->arg2 = NULL;
2066 err->flags = 0;
2067 }
2068 }
2069 ctxt->errNr = level;
2070}
2071/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002072 * xmlRelaxNGDumpValidError:
2073 * @ctxt: the validation context
2074 *
2075 * Show all validation error over a given index.
2076 */
2077static void
2078xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
2079 int i;
2080 xmlRelaxNGValidErrorPtr err;
2081
2082 for (i = 0;i < ctxt->errNr;i++) {
2083 err = &ctxt->errTab[i];
2084 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2085 err->arg1, err->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002086 if (err->flags & ERROR_IS_DUP) {
2087 if (err->arg1 != NULL)
2088 xmlFree((xmlChar *)err->arg1);
2089 err->arg1 = NULL;
2090 if (err->arg2 != NULL)
2091 xmlFree((xmlChar *)err->arg2);
2092 err->arg2 = NULL;
2093 err->flags = 0;
2094 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002095 }
2096 ctxt->errNr = 0;
2097}
2098/**
2099 * xmlRelaxNGAddValidError:
2100 * @ctxt: the validation context
2101 * @err: the error number
2102 * @arg1: the first argument
2103 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002104 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002105 *
2106 * Register a validation error, either generating it if it's sure
2107 * or stacking it for later handling if unsure.
2108 */
2109static void
2110xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002111 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002112{
2113 if ((ctxt == NULL) || (ctxt->error == NULL))
2114 return;
2115
2116 /*
2117 * generate the error directly
2118 */
2119 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2120 xmlNodePtr node, seq;
2121 /*
2122 * Flush first any stacked error which might be the
2123 * real cause of the problem.
2124 */
2125 if (ctxt->errNr != 0)
2126 xmlRelaxNGDumpValidError(ctxt);
2127 if (ctxt->state != NULL) {
2128 node = ctxt->state->node;
2129 seq = ctxt->state->seq;
2130 } else {
2131 node = seq = NULL;
2132 }
2133 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2134 }
2135 /*
2136 * Stack the error for later processing if needed
2137 */
2138 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002139 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002140 }
2141}
2142
Daniel Veillard6eadf632003-01-23 18:29:16 +00002143
2144/************************************************************************
2145 * *
2146 * Type library hooks *
2147 * *
2148 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002149static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2150 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002151
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002152/**
2153 * xmlRelaxNGSchemaTypeHave:
2154 * @data: data needed for the library
2155 * @type: the type name
2156 *
2157 * Check if the given type is provided by
2158 * the W3C XMLSchema Datatype library.
2159 *
2160 * Returns 1 if yes, 0 if no and -1 in case of error.
2161 */
2162static int
2163xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002164 const xmlChar *type) {
2165 xmlSchemaTypePtr typ;
2166
2167 if (type == NULL)
2168 return(-1);
2169 typ = xmlSchemaGetPredefinedType(type,
2170 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2171 if (typ == NULL)
2172 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002173 return(1);
2174}
2175
2176/**
2177 * xmlRelaxNGSchemaTypeCheck:
2178 * @data: data needed for the library
2179 * @type: the type name
2180 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002181 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002182 *
2183 * Check if the given type and value are validated by
2184 * the W3C XMLSchema Datatype library.
2185 *
2186 * Returns 1 if yes, 0 if no and -1 in case of error.
2187 */
2188static int
2189xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002190 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002191 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002192 void **result,
2193 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002194 xmlSchemaTypePtr typ;
2195 int ret;
2196
2197 /*
2198 * TODO: the type should be cached ab provided back, interface subject
2199 * to changes.
2200 * TODO: handle facets, may require an additional interface and keep
2201 * the value returned from the validation.
2202 */
2203 if ((type == NULL) || (value == NULL))
2204 return(-1);
2205 typ = xmlSchemaGetPredefinedType(type,
2206 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2207 if (typ == NULL)
2208 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002209 ret = xmlSchemaValPredefTypeNode(typ, value,
2210 (xmlSchemaValPtr *) result, node);
2211 if (ret == 2) /* special ID error code */
2212 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002213 if (ret == 0)
2214 return(1);
2215 if (ret > 0)
2216 return(0);
2217 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002218}
2219
2220/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002221 * xmlRelaxNGSchemaFacetCheck:
2222 * @data: data needed for the library
2223 * @type: the type name
2224 * @facet: the facet name
2225 * @val: the facet value
2226 * @strval: the string value
2227 * @value: the value to check
2228 *
2229 * Function provided by a type library to check a value facet
2230 *
2231 * Returns 1 if yes, 0 if no and -1 in case of error.
2232 */
2233static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002234xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002235 const xmlChar *facetname, const xmlChar *val,
2236 const xmlChar *strval, void *value) {
2237 xmlSchemaFacetPtr facet;
2238 xmlSchemaTypePtr typ;
2239 int ret;
2240
2241 if ((type == NULL) || (strval == NULL))
2242 return(-1);
2243 typ = xmlSchemaGetPredefinedType(type,
2244 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2245 if (typ == NULL)
2246 return(-1);
2247
2248 facet = xmlSchemaNewFacet();
2249 if (facet == NULL)
2250 return(-1);
2251
2252 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2253 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2254 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2255 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2256 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2257 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2258 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2259 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2260 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2261 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2262 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2263 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2264 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2265 facet->type = XML_SCHEMA_FACET_PATTERN;
2266 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2267 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2268 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2269 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2270 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2271 facet->type = XML_SCHEMA_FACET_LENGTH;
2272 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2273 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2274 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2275 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2276 } else {
2277 xmlSchemaFreeFacet(facet);
2278 return(-1);
2279 }
2280 facet->value = xmlStrdup(val);
2281 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2282 if (ret != 0) {
2283 xmlSchemaFreeFacet(facet);
2284 return(-1);
2285 }
2286 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2287 xmlSchemaFreeFacet(facet);
2288 if (ret != 0)
2289 return(-1);
2290 return(0);
2291}
2292
2293/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002294 * xmlRelaxNGSchemaTypeCompare:
2295 * @data: data needed for the library
2296 * @type: the type name
2297 * @value1: the first value
2298 * @value2: the second value
2299 *
2300 * Compare two values accordingly a type from the W3C XMLSchema
2301 * Datatype library.
2302 *
2303 * Returns 1 if yes, 0 if no and -1 in case of error.
2304 */
2305static int
2306xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2307 const xmlChar *type ATTRIBUTE_UNUSED,
2308 const xmlChar *value1 ATTRIBUTE_UNUSED,
2309 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2310 TODO
2311 return(1);
2312}
2313
2314/**
2315 * xmlRelaxNGDefaultTypeHave:
2316 * @data: data needed for the library
2317 * @type: the type name
2318 *
2319 * Check if the given type is provided by
2320 * the default datatype library.
2321 *
2322 * Returns 1 if yes, 0 if no and -1 in case of error.
2323 */
2324static int
2325xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2326 if (type == NULL)
2327 return(-1);
2328 if (xmlStrEqual(type, BAD_CAST "string"))
2329 return(1);
2330 if (xmlStrEqual(type, BAD_CAST "token"))
2331 return(1);
2332 return(0);
2333}
2334
2335/**
2336 * xmlRelaxNGDefaultTypeCheck:
2337 * @data: data needed for the library
2338 * @type: the type name
2339 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002340 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002341 *
2342 * Check if the given type and value are validated by
2343 * the default datatype library.
2344 *
2345 * Returns 1 if yes, 0 if no and -1 in case of error.
2346 */
2347static int
2348xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2349 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002350 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002351 void **result ATTRIBUTE_UNUSED,
2352 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002353 if (value == NULL)
2354 return(-1);
2355 if (xmlStrEqual(type, BAD_CAST "string"))
2356 return(1);
2357 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002358 return(1);
2359 }
2360
2361 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002362}
2363
2364/**
2365 * xmlRelaxNGDefaultTypeCompare:
2366 * @data: data needed for the library
2367 * @type: the type name
2368 * @value1: the first value
2369 * @value2: the second value
2370 *
2371 * Compare two values accordingly a type from the default
2372 * datatype library.
2373 *
2374 * Returns 1 if yes, 0 if no and -1 in case of error.
2375 */
2376static int
2377xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2378 const xmlChar *type ATTRIBUTE_UNUSED,
2379 const xmlChar *value1 ATTRIBUTE_UNUSED,
2380 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002381 int ret = -1;
2382
2383 if (xmlStrEqual(type, BAD_CAST "string")) {
2384 ret = xmlStrEqual(value1, value2);
2385 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2386 if (!xmlStrEqual(value1, value2)) {
2387 xmlChar *nval, *nvalue;
2388
2389 /*
2390 * TODO: trivial optimizations are possible by
2391 * computing at compile-time
2392 */
2393 nval = xmlRelaxNGNormalize(NULL, value1);
2394 nvalue = xmlRelaxNGNormalize(NULL, value2);
2395
Daniel Veillardd4310742003-02-18 21:12:46 +00002396 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002397 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002398 else if (xmlStrEqual(nval, nvalue))
2399 ret = 1;
2400 else
2401 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002402 if (nval != NULL)
2403 xmlFree(nval);
2404 if (nvalue != NULL)
2405 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002406 } else
2407 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002408 }
2409 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002410}
2411
2412static int xmlRelaxNGTypeInitialized = 0;
2413static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2414
2415/**
2416 * xmlRelaxNGFreeTypeLibrary:
2417 * @lib: the type library structure
2418 * @namespace: the URI bound to the library
2419 *
2420 * Free the structure associated to the type library
2421 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002422static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002423xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2424 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2425 if (lib == NULL)
2426 return;
2427 if (lib->namespace != NULL)
2428 xmlFree((xmlChar *)lib->namespace);
2429 xmlFree(lib);
2430}
2431
2432/**
2433 * xmlRelaxNGRegisterTypeLibrary:
2434 * @namespace: the URI bound to the library
2435 * @data: data associated to the library
2436 * @have: the provide function
2437 * @check: the checking function
2438 * @comp: the comparison function
2439 *
2440 * Register a new type library
2441 *
2442 * Returns 0 in case of success and -1 in case of error.
2443 */
2444static int
2445xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2446 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002447 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2448 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002449 xmlRelaxNGTypeLibraryPtr lib;
2450 int ret;
2451
2452 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2453 (check == NULL) || (comp == NULL))
2454 return(-1);
2455 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2456 xmlGenericError(xmlGenericErrorContext,
2457 "Relax-NG types library '%s' already registered\n",
2458 namespace);
2459 return(-1);
2460 }
2461 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2462 if (lib == NULL) {
2463 xmlGenericError(xmlGenericErrorContext,
2464 "Relax-NG types library '%s' malloc() failed\n",
2465 namespace);
2466 return (-1);
2467 }
2468 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2469 lib->namespace = xmlStrdup(namespace);
2470 lib->data = data;
2471 lib->have = have;
2472 lib->comp = comp;
2473 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002474 lib->facet = facet;
2475 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002476 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2477 if (ret < 0) {
2478 xmlGenericError(xmlGenericErrorContext,
2479 "Relax-NG types library failed to register '%s'\n",
2480 namespace);
2481 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2482 return(-1);
2483 }
2484 return(0);
2485}
2486
2487/**
2488 * xmlRelaxNGInitTypes:
2489 *
2490 * Initilize the default type libraries.
2491 *
2492 * Returns 0 in case of success and -1 in case of error.
2493 */
2494static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002495xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002496 if (xmlRelaxNGTypeInitialized != 0)
2497 return(0);
2498 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2499 if (xmlRelaxNGRegisteredTypes == NULL) {
2500 xmlGenericError(xmlGenericErrorContext,
2501 "Failed to allocate sh table for Relax-NG types\n");
2502 return(-1);
2503 }
2504 xmlRelaxNGRegisterTypeLibrary(
2505 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2506 NULL,
2507 xmlRelaxNGSchemaTypeHave,
2508 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002509 xmlRelaxNGSchemaTypeCompare,
2510 xmlRelaxNGSchemaFacetCheck,
2511 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002512 xmlRelaxNGRegisterTypeLibrary(
2513 xmlRelaxNGNs,
2514 NULL,
2515 xmlRelaxNGDefaultTypeHave,
2516 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002517 xmlRelaxNGDefaultTypeCompare,
2518 NULL,
2519 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002520 xmlRelaxNGTypeInitialized = 1;
2521 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002522}
2523
2524/**
2525 * xmlRelaxNGCleanupTypes:
2526 *
2527 * Cleanup the default Schemas type library associated to RelaxNG
2528 */
2529void
2530xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002531 if (xmlRelaxNGTypeInitialized == 0)
2532 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002533 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002534 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2535 xmlRelaxNGFreeTypeLibrary);
2536 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002537}
2538
2539/************************************************************************
2540 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002541 * Compiling element content into regexp *
2542 * *
2543 * Sometime the element content can be compiled into a pure regexp, *
2544 * This allows a faster execution and streamability at that level *
2545 * *
2546 ************************************************************************/
2547
2548/**
2549 * xmlRelaxNGIsCompileable:
2550 * @define: the definition to check
2551 *
2552 * Check if a definition is nullable.
2553 *
2554 * Returns 1 if yes, 0 if no and -1 in case of error
2555 */
2556static int
2557xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2558 if (def == NULL) {
2559 return(-1);
2560 }
2561 switch(def->type) {
2562 case XML_RELAXNG_REF:
2563 case XML_RELAXNG_EXTERNALREF:
2564 case XML_RELAXNG_PARENTREF:
2565 case XML_RELAXNG_NOOP:
2566 case XML_RELAXNG_START:
2567 return(xmlRelaxNGIsCompileable(def->content));
2568 case XML_RELAXNG_TEXT:
2569 case XML_RELAXNG_DATATYPE:
2570 case XML_RELAXNG_LIST:
2571 case XML_RELAXNG_PARAM:
2572 case XML_RELAXNG_VALUE:
2573
2574 case XML_RELAXNG_EMPTY:
2575 case XML_RELAXNG_ELEMENT:
2576 return(1);
2577 case XML_RELAXNG_OPTIONAL:
2578 case XML_RELAXNG_ZEROORMORE:
2579 case XML_RELAXNG_ONEORMORE:
2580 case XML_RELAXNG_CHOICE:
2581 case XML_RELAXNG_GROUP:
2582 case XML_RELAXNG_DEF: {
2583 xmlRelaxNGDefinePtr list;
2584 int ret;
2585
2586 list = def->content;
2587 while (list != NULL) {
2588 ret = xmlRelaxNGIsCompileable(list);
2589 if (ret != 1)
2590 return(ret);
2591 list = list->next;
2592 }
2593 return(1);
2594 }
2595 case XML_RELAXNG_EXCEPT:
2596 case XML_RELAXNG_ATTRIBUTE:
2597 case XML_RELAXNG_INTERLEAVE:
2598 return(0);
2599 case XML_RELAXNG_NOT_ALLOWED:
2600 return(-1);
2601 }
2602 return(-1);
2603}
2604
2605/************************************************************************
2606 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002607 * Parsing functions *
2608 * *
2609 ************************************************************************/
2610
2611static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2612 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2613static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2614 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2615static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002616 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002617static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2618 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002619static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2620 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002621static int xmlRelaxNGParseGrammarContent(
2622 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002623static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2624 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2625 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002626static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2627 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002628static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2629 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002630
2631
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002632#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002633
2634/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002635 * xmlRelaxNGIsNullable:
2636 * @define: the definition to verify
2637 *
2638 * Check if a definition is nullable.
2639 *
2640 * Returns 1 if yes, 0 if no and -1 in case of error
2641 */
2642static int
2643xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2644 int ret;
2645 if (define == NULL)
2646 return(-1);
2647
2648 if (define->flags & IS_NULLABLE)
2649 return(1);
2650 if (define->flags & IS_NOT_NULLABLE)
2651 return(0);
2652 switch (define->type) {
2653 case XML_RELAXNG_EMPTY:
2654 case XML_RELAXNG_TEXT:
2655 ret = 1; break;
2656 case XML_RELAXNG_NOOP:
2657 case XML_RELAXNG_DEF:
2658 case XML_RELAXNG_REF:
2659 case XML_RELAXNG_EXTERNALREF:
2660 case XML_RELAXNG_PARENTREF:
2661 case XML_RELAXNG_ONEORMORE:
2662 ret = xmlRelaxNGIsNullable(define->content);
2663 break;
2664 case XML_RELAXNG_EXCEPT:
2665 case XML_RELAXNG_NOT_ALLOWED:
2666 case XML_RELAXNG_ELEMENT:
2667 case XML_RELAXNG_DATATYPE:
2668 case XML_RELAXNG_PARAM:
2669 case XML_RELAXNG_VALUE:
2670 case XML_RELAXNG_LIST:
2671 case XML_RELAXNG_ATTRIBUTE:
2672 ret = 0; break;
2673 case XML_RELAXNG_CHOICE: {
2674 xmlRelaxNGDefinePtr list = define->content;
2675
2676 while (list != NULL) {
2677 ret = xmlRelaxNGIsNullable(list);
2678 if (ret != 0)
2679 goto done;
2680 list = list->next;
2681 }
2682 ret = 0; break;
2683 }
2684 case XML_RELAXNG_START:
2685 case XML_RELAXNG_INTERLEAVE:
2686 case XML_RELAXNG_GROUP: {
2687 xmlRelaxNGDefinePtr list = define->content;
2688
2689 while (list != NULL) {
2690 ret = xmlRelaxNGIsNullable(list);
2691 if (ret != 1)
2692 goto done;
2693 list = list->next;
2694 }
2695 return(1);
2696 }
2697 default:
2698 return(-1);
2699 }
2700done:
2701 if (ret == 0)
2702 define->flags |= IS_NOT_NULLABLE;
2703 if (ret == 1)
2704 define->flags |= IS_NULLABLE;
2705 return(ret);
2706}
2707
2708/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002709 * xmlRelaxNGIsBlank:
2710 * @str: a string
2711 *
2712 * Check if a string is ignorable c.f. 4.2. Whitespace
2713 *
2714 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2715 */
2716static int
2717xmlRelaxNGIsBlank(xmlChar *str) {
2718 if (str == NULL)
2719 return(1);
2720 while (*str != 0) {
2721 if (!(IS_BLANK(*str))) return(0);
2722 str++;
2723 }
2724 return(1);
2725}
2726
Daniel Veillard6eadf632003-01-23 18:29:16 +00002727/**
2728 * xmlRelaxNGGetDataTypeLibrary:
2729 * @ctxt: a Relax-NG parser context
2730 * @node: the current data or value element
2731 *
2732 * Applies algorithm from 4.3. datatypeLibrary attribute
2733 *
2734 * Returns the datatypeLibary value or NULL if not found
2735 */
2736static xmlChar *
2737xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2738 xmlNodePtr node) {
2739 xmlChar *ret, *escape;
2740
Daniel Veillard6eadf632003-01-23 18:29:16 +00002741 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2742 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2743 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002744 if (ret[0] == 0) {
2745 xmlFree(ret);
2746 return(NULL);
2747 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002748 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002749 if (escape == NULL) {
2750 return(ret);
2751 }
2752 xmlFree(ret);
2753 return(escape);
2754 }
2755 }
2756 node = node->parent;
2757 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002758 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2759 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002760 if (ret[0] == 0) {
2761 xmlFree(ret);
2762 return(NULL);
2763 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002764 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2765 if (escape == NULL) {
2766 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002767 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002768 xmlFree(ret);
2769 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002770 }
2771 node = node->parent;
2772 }
2773 return(NULL);
2774}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002775
2776/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002777 * xmlRelaxNGParseValue:
2778 * @ctxt: a Relax-NG parser context
2779 * @node: the data node.
2780 *
2781 * parse the content of a RelaxNG value node.
2782 *
2783 * Returns the definition pointer or NULL in case of error
2784 */
2785static xmlRelaxNGDefinePtr
2786xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2787 xmlRelaxNGDefinePtr def = NULL;
2788 xmlRelaxNGTypeLibraryPtr lib;
2789 xmlChar *type;
2790 xmlChar *library;
2791 int tmp;
2792
Daniel Veillardfd573f12003-03-16 17:52:32 +00002793 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002794 if (def == NULL)
2795 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002796 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002797
2798 type = xmlGetProp(node, BAD_CAST "type");
2799 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002800 xmlRelaxNGNormExtSpace(type);
2801 if (xmlValidateNCName(type, 0)) {
2802 if (ctxt->error != NULL)
2803 ctxt->error(ctxt->userData,
2804 "value type '%s' is not an NCName\n",
2805 type);
2806 ctxt->nbErrors++;
2807 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002808 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2809 if (library == NULL)
2810 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2811
2812 def->name = type;
2813 def->ns = library;
2814
2815 lib = (xmlRelaxNGTypeLibraryPtr)
2816 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2817 if (lib == NULL) {
2818 if (ctxt->error != NULL)
2819 ctxt->error(ctxt->userData,
2820 "Use of unregistered type library '%s'\n",
2821 library);
2822 ctxt->nbErrors++;
2823 def->data = NULL;
2824 } else {
2825 def->data = lib;
2826 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002827 if (ctxt->error != NULL)
2828 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002829 "Internal error with type library '%s': no 'have'\n",
2830 library);
2831 ctxt->nbErrors++;
2832 } else {
2833 tmp = lib->have(lib->data, def->name);
2834 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002835 if (ctxt->error != NULL)
2836 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002837 "Error type '%s' is not exported by type library '%s'\n",
2838 def->name, library);
2839 ctxt->nbErrors++;
2840 }
2841 }
2842 }
2843 }
2844 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002845 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002846 } else if (((node->children->type != XML_TEXT_NODE) &&
2847 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002848 (node->children->next != NULL)) {
2849 if (ctxt->error != NULL)
2850 ctxt->error(ctxt->userData,
2851 "Expecting a single text value for <value>content\n");
2852 ctxt->nbErrors++;
2853 } else {
2854 def->value = xmlNodeGetContent(node);
2855 if (def->value == NULL) {
2856 if (ctxt->error != NULL)
2857 ctxt->error(ctxt->userData,
2858 "Element <value> has no content\n");
2859 ctxt->nbErrors++;
2860 }
2861 }
2862 /* TODO check ahead of time that the value is okay per the type */
2863 return(def);
2864}
2865
2866/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002867 * xmlRelaxNGParseData:
2868 * @ctxt: a Relax-NG parser context
2869 * @node: the data node.
2870 *
2871 * parse the content of a RelaxNG data node.
2872 *
2873 * Returns the definition pointer or NULL in case of error
2874 */
2875static xmlRelaxNGDefinePtr
2876xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002877 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002878 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002879 xmlRelaxNGTypeLibraryPtr lib;
2880 xmlChar *type;
2881 xmlChar *library;
2882 xmlNodePtr content;
2883 int tmp;
2884
2885 type = xmlGetProp(node, BAD_CAST "type");
2886 if (type == NULL) {
2887 if (ctxt->error != NULL)
2888 ctxt->error(ctxt->userData,
2889 "data has no type\n");
2890 ctxt->nbErrors++;
2891 return(NULL);
2892 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002893 xmlRelaxNGNormExtSpace(type);
2894 if (xmlValidateNCName(type, 0)) {
2895 if (ctxt->error != NULL)
2896 ctxt->error(ctxt->userData,
2897 "data type '%s' is not an NCName\n",
2898 type);
2899 ctxt->nbErrors++;
2900 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002901 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2902 if (library == NULL)
2903 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2904
Daniel Veillardfd573f12003-03-16 17:52:32 +00002905 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002906 if (def == NULL) {
2907 xmlFree(type);
2908 return(NULL);
2909 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002910 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002911 def->name = type;
2912 def->ns = library;
2913
2914 lib = (xmlRelaxNGTypeLibraryPtr)
2915 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2916 if (lib == NULL) {
2917 if (ctxt->error != NULL)
2918 ctxt->error(ctxt->userData,
2919 "Use of unregistered type library '%s'\n",
2920 library);
2921 ctxt->nbErrors++;
2922 def->data = NULL;
2923 } else {
2924 def->data = lib;
2925 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002926 if (ctxt->error != NULL)
2927 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002928 "Internal error with type library '%s': no 'have'\n",
2929 library);
2930 ctxt->nbErrors++;
2931 } else {
2932 tmp = lib->have(lib->data, def->name);
2933 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002934 if (ctxt->error != NULL)
2935 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002936 "Error type '%s' is not exported by type library '%s'\n",
2937 def->name, library);
2938 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002939 } else if ((xmlStrEqual(library, BAD_CAST
2940 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
2941 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
2942 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
2943 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002944 }
2945 }
2946 }
2947 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002948
2949 /*
2950 * Handle optional params
2951 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002952 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002953 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2954 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002955 if (xmlStrEqual(library,
2956 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2957 if (ctxt->error != NULL)
2958 ctxt->error(ctxt->userData,
2959 "Type library '%s' does not allow type parameters\n",
2960 library);
2961 ctxt->nbErrors++;
2962 content = content->next;
2963 while ((content != NULL) &&
2964 (xmlStrEqual(content->name, BAD_CAST "param")))
2965 content = content->next;
2966 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002967 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002968 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002969 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002970 param->name = xmlGetProp(content, BAD_CAST "name");
2971 if (param->name == NULL) {
2972 if (ctxt->error != NULL)
2973 ctxt->error(ctxt->userData,
2974 "param has no name\n");
2975 ctxt->nbErrors++;
2976 }
2977 param->value = xmlNodeGetContent(content);
2978 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002979 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002980 } else {
2981 lastparam->next = param;
2982 lastparam = param;
2983 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002984 if (lib != NULL) {
2985 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002986 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002987 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002988 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002989 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002990 /*
2991 * Handle optional except
2992 */
2993 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2994 xmlNodePtr child;
2995 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2996
Daniel Veillardfd573f12003-03-16 17:52:32 +00002997 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00002998 if (except == NULL) {
2999 return(def);
3000 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003001 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003002 child = content->children;
3003 if (last == NULL) {
3004 def->content = except;
3005 } else {
3006 last->next = except;
3007 }
3008 if (child == NULL) {
3009 if (ctxt->error != NULL)
3010 ctxt->error(ctxt->userData,
3011 "except has no content\n");
3012 ctxt->nbErrors++;
3013 }
3014 while (child != NULL) {
3015 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3016 if (tmp2 != NULL) {
3017 if (last2 == NULL) {
3018 except->content = last2 = tmp2;
3019 } else {
3020 last2->next = tmp2;
3021 last2 = tmp2;
3022 }
3023 }
3024 child = child->next;
3025 }
3026 content = content->next;
3027 }
3028 /*
3029 * Check there is no unhandled data
3030 */
3031 if (content != NULL) {
3032 if (ctxt->error != NULL)
3033 ctxt->error(ctxt->userData,
3034 "Element data has unexpected content %s\n", content->name);
3035 ctxt->nbErrors++;
3036 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003037
3038 return(def);
3039}
3040
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003041static const xmlChar *invalidName = BAD_CAST "\1";
3042
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003043/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003044 * xmlRelaxNGCompareNameClasses:
3045 * @defs1: the first element/attribute defs
3046 * @defs2: the second element/attribute defs
3047 * @name: the restriction on the name
3048 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003049 *
3050 * Compare the 2 lists of element definitions. The comparison is
3051 * that if both lists do not accept the same QNames, it returns 1
3052 * If the 2 lists can accept the same QName the comparison returns 0
3053 *
3054 * Returns 1 disttinct, 0 if equal
3055 */
3056static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003057xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3058 xmlRelaxNGDefinePtr def2) {
3059 int ret = 1;
3060 xmlNode node;
3061 xmlNs ns;
3062 xmlRelaxNGValidCtxt ctxt;
3063 ctxt.flags = FLAGS_IGNORABLE;
3064
Daniel Veillard42f12e92003-03-07 18:32:59 +00003065 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3066
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003067 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3068 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3069 if (def2->type == XML_RELAXNG_TEXT)
3070 return(1);
3071 if (def1->name != NULL) {
3072 node.name = def1->name;
3073 } else {
3074 node.name = invalidName;
3075 }
3076 node.ns = &ns;
3077 if (def1->ns != NULL) {
3078 if (def1->ns[0] == 0) {
3079 node.ns = NULL;
3080 } else {
3081 ns.href = def1->ns;
3082 }
3083 } else {
3084 ns.href = invalidName;
3085 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003086 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003087 if (def1->nameClass != NULL) {
3088 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3089 } else {
3090 ret = 0;
3091 }
3092 } else {
3093 ret = 1;
3094 }
3095 } else if (def1->type == XML_RELAXNG_TEXT) {
3096 if (def2->type == XML_RELAXNG_TEXT)
3097 return(0);
3098 return(1);
3099 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003100 TODO
3101 ret = 0;
3102 } else {
3103 TODO
3104 ret = 0;
3105 }
3106 if (ret == 0)
3107 return(ret);
3108 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3109 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3110 if (def2->name != NULL) {
3111 node.name = def2->name;
3112 } else {
3113 node.name = invalidName;
3114 }
3115 node.ns = &ns;
3116 if (def2->ns != NULL) {
3117 if (def2->ns[0] == 0) {
3118 node.ns = NULL;
3119 } else {
3120 ns.href = def2->ns;
3121 }
3122 } else {
3123 ns.href = invalidName;
3124 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003125 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003126 if (def2->nameClass != NULL) {
3127 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3128 } else {
3129 ret = 0;
3130 }
3131 } else {
3132 ret = 1;
3133 }
3134 } else {
3135 TODO
3136 ret = 0;
3137 }
3138
3139 return(ret);
3140}
3141
3142/**
3143 * xmlRelaxNGCompareElemDefLists:
3144 * @ctxt: a Relax-NG parser context
3145 * @defs1: the first list of element/attribute defs
3146 * @defs2: the second list of element/attribute defs
3147 *
3148 * Compare the 2 lists of element or attribute definitions. The comparison
3149 * is that if both lists do not accept the same QNames, it returns 1
3150 * If the 2 lists can accept the same QName the comparison returns 0
3151 *
3152 * Returns 1 disttinct, 0 if equal
3153 */
3154static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003155xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3156 xmlRelaxNGDefinePtr *def1,
3157 xmlRelaxNGDefinePtr *def2) {
3158 xmlRelaxNGDefinePtr *basedef2 = def2;
3159
Daniel Veillard154877e2003-01-30 12:17:05 +00003160 if ((def1 == NULL) || (def2 == NULL))
3161 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003162 if ((*def1 == NULL) || (*def2 == NULL))
3163 return(1);
3164 while (*def1 != NULL) {
3165 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003166 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3167 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003168 def2++;
3169 }
3170 def2 = basedef2;
3171 def1++;
3172 }
3173 return(1);
3174}
3175
3176/**
3177 * xmlRelaxNGGetElements:
3178 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003179 * @def: the definition definition
3180 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003181 *
3182 * Compute the list of top elements a definition can generate
3183 *
3184 * Returns a list of elements or NULL if none was found.
3185 */
3186static xmlRelaxNGDefinePtr *
3187xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003188 xmlRelaxNGDefinePtr def,
3189 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003190 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003191 int len = 0;
3192 int max = 0;
3193
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003194 /*
3195 * Don't run that check in case of error. Infinite recursion
3196 * becomes possible.
3197 */
3198 if (ctxt->nbErrors != 0)
3199 return(NULL);
3200
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003201 parent = NULL;
3202 cur = def;
3203 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003204 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3205 (cur->type == XML_RELAXNG_TEXT))) ||
3206 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003207 if (ret == NULL) {
3208 max = 10;
3209 ret = (xmlRelaxNGDefinePtr *)
3210 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3211 if (ret == NULL) {
3212 if (ctxt->error != NULL)
3213 ctxt->error(ctxt->userData,
3214 "Out of memory in element search\n");
3215 ctxt->nbErrors++;
3216 return(NULL);
3217 }
3218 } else if (max <= len) {
3219 max *= 2;
3220 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3221 if (ret == NULL) {
3222 if (ctxt->error != NULL)
3223 ctxt->error(ctxt->userData,
3224 "Out of memory in element search\n");
3225 ctxt->nbErrors++;
3226 return(NULL);
3227 }
3228 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003229 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003230 ret[len] = NULL;
3231 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3232 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3233 (cur->type == XML_RELAXNG_GROUP) ||
3234 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003235 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3236 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003237 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003238 (cur->type == XML_RELAXNG_REF) ||
3239 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003240 /*
3241 * Don't go within elements or attributes or string values.
3242 * Just gather the element top list
3243 */
3244 if (cur->content != NULL) {
3245 parent = cur;
3246 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003247 tmp = cur;
3248 while (tmp != NULL) {
3249 tmp->parent = parent;
3250 tmp = tmp->next;
3251 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003252 continue;
3253 }
3254 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003255 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003256 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003257 if (cur->next != NULL) {
3258 cur = cur->next;
3259 continue;
3260 }
3261 do {
3262 cur = cur->parent;
3263 if (cur == NULL) break;
3264 if (cur == def) return(ret);
3265 if (cur->next != NULL) {
3266 cur = cur->next;
3267 break;
3268 }
3269 } while (cur != NULL);
3270 }
3271 return(ret);
3272}
3273
3274/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003275 * xmlRelaxNGCheckChoiceDeterminism:
3276 * @ctxt: a Relax-NG parser context
3277 * @def: the choice definition
3278 *
3279 * Also used to find indeterministic pattern in choice
3280 */
3281static void
3282xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3283 xmlRelaxNGDefinePtr def) {
3284 xmlRelaxNGDefinePtr **list;
3285 xmlRelaxNGDefinePtr cur;
3286 int nbchild = 0, i, j, ret;
3287 int is_nullable = 0;
3288 int is_indeterminist = 0;
3289
3290 if ((def == NULL) ||
3291 (def->type != XML_RELAXNG_CHOICE))
3292 return;
3293
3294 /*
3295 * Don't run that check in case of error. Infinite recursion
3296 * becomes possible.
3297 */
3298 if (ctxt->nbErrors != 0)
3299 return;
3300
3301 is_nullable = xmlRelaxNGIsNullable(def);
3302
3303 cur = def->content;
3304 while (cur != NULL) {
3305 nbchild++;
3306 cur = cur->next;
3307 }
3308
3309 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3310 sizeof(xmlRelaxNGDefinePtr *));
3311 if (list == NULL) {
3312 if (ctxt->error != NULL)
3313 ctxt->error(ctxt->userData,
3314 "Out of memory in choice computation\n");
3315 ctxt->nbErrors++;
3316 return;
3317 }
3318 i = 0;
3319 cur = def->content;
3320 while (cur != NULL) {
3321 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
3322 i++;
3323 cur = cur->next;
3324 }
3325
3326 for (i = 0;i < nbchild;i++) {
3327 if (list[i] == NULL)
3328 continue;
3329 for (j = 0;j < i;j++) {
3330 if (list[j] == NULL)
3331 continue;
3332 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3333 if (ret == 0) {
3334 is_indeterminist = 1;
3335 }
3336 }
3337 }
3338 for (i = 0;i < nbchild;i++) {
3339 if (list[i] != NULL)
3340 xmlFree(list[i]);
3341 }
3342
3343 xmlFree(list);
3344 if (is_indeterminist) {
3345 def->flags |= IS_INDETERMINIST;
3346 }
3347}
3348
3349/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003350 * xmlRelaxNGCheckGroupAttrs:
3351 * @ctxt: a Relax-NG parser context
3352 * @def: the group definition
3353 *
3354 * Detects violations of rule 7.3
3355 */
3356static void
3357xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3358 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003359 xmlRelaxNGDefinePtr **list;
3360 xmlRelaxNGDefinePtr cur;
3361 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003362
3363 if ((def == NULL) ||
3364 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003365 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003366 return;
3367
3368 /*
3369 * Don't run that check in case of error. Infinite recursion
3370 * becomes possible.
3371 */
3372 if (ctxt->nbErrors != 0)
3373 return;
3374
Daniel Veillardfd573f12003-03-16 17:52:32 +00003375 cur = def->attrs;
3376 while (cur != NULL) {
3377 nbchild++;
3378 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003379 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003380 cur = def->content;
3381 while (cur != NULL) {
3382 nbchild++;
3383 cur = cur->next;
3384 }
3385
3386 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3387 sizeof(xmlRelaxNGDefinePtr *));
3388 if (list == NULL) {
3389 if (ctxt->error != NULL)
3390 ctxt->error(ctxt->userData,
3391 "Out of memory in group computation\n");
3392 ctxt->nbErrors++;
3393 return;
3394 }
3395 i = 0;
3396 cur = def->attrs;
3397 while (cur != NULL) {
3398 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3399 i++;
3400 cur = cur->next;
3401 }
3402 cur = def->content;
3403 while (cur != NULL) {
3404 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3405 i++;
3406 cur = cur->next;
3407 }
3408
3409 for (i = 0;i < nbchild;i++) {
3410 if (list[i] == NULL)
3411 continue;
3412 for (j = 0;j < i;j++) {
3413 if (list[j] == NULL)
3414 continue;
3415 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3416 if (ret == 0) {
3417 if (ctxt->error != NULL)
3418 ctxt->error(ctxt->userData,
3419 "Attributes conflicts in group\n");
3420 ctxt->nbErrors++;
3421 }
3422 }
3423 }
3424 for (i = 0;i < nbchild;i++) {
3425 if (list[i] != NULL)
3426 xmlFree(list[i]);
3427 }
3428
3429 xmlFree(list);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003430}
3431
3432/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003433 * xmlRelaxNGComputeInterleaves:
3434 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003435 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003436 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003437 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003438 * A lot of work for preprocessing interleave definitions
3439 * is potentially needed to get a decent execution speed at runtime
3440 * - trying to get a total order on the element nodes generated
3441 * by the interleaves, order the list of interleave definitions
3442 * following that order.
3443 * - if <text/> is used to handle mixed content, it is better to
3444 * flag this in the define and simplify the runtime checking
3445 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003446 */
3447static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003448xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3449 xmlRelaxNGParserCtxtPtr ctxt,
3450 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003451 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003452
Daniel Veillardfd573f12003-03-16 17:52:32 +00003453 xmlRelaxNGPartitionPtr partitions = NULL;
3454 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3455 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003456 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003457 int nbgroups = 0;
3458 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003459 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003460 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003461
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003462 /*
3463 * Don't run that check in case of error. Infinite recursion
3464 * becomes possible.
3465 */
3466 if (ctxt->nbErrors != 0)
3467 return;
3468
Daniel Veillardfd573f12003-03-16 17:52:32 +00003469#ifdef DEBUG_INTERLEAVE
3470 xmlGenericError(xmlGenericErrorContext,
3471 "xmlRelaxNGComputeInterleaves(%s)\n",
3472 name);
3473#endif
3474 cur = def->content;
3475 while (cur != NULL) {
3476 nbchild++;
3477 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003478 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003479
3480#ifdef DEBUG_INTERLEAVE
3481 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3482#endif
3483 groups = (xmlRelaxNGInterleaveGroupPtr *)
3484 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3485 if (groups == NULL)
3486 goto error;
3487 cur = def->content;
3488 while (cur != NULL) {
3489 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3490 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3491 if (groups[nbgroups] == NULL)
3492 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003493 if (cur->type == XML_RELAXNG_TEXT)
3494 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003495 groups[nbgroups]->rule = cur;
3496 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3497 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3498 nbgroups++;
3499 cur = cur->next;
3500 }
3501#ifdef DEBUG_INTERLEAVE
3502 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3503#endif
3504
3505 /*
3506 * Let's check that all rules makes a partitions according to 7.4
3507 */
3508 partitions = (xmlRelaxNGPartitionPtr)
3509 xmlMalloc(sizeof(xmlRelaxNGPartition));
3510 if (partitions == NULL)
3511 goto error;
3512 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003513 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003514 for (i = 0;i < nbgroups;i++) {
3515 group = groups[i];
3516 for (j = i+1;j < nbgroups;j++) {
3517 if (groups[j] == NULL)
3518 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003519
Daniel Veillardfd573f12003-03-16 17:52:32 +00003520 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3521 groups[j]->defs);
3522 if (ret == 0) {
3523 if (ctxt->error != NULL)
3524 ctxt->error(ctxt->userData,
3525 "Element or text conflicts in interleave\n");
3526 ctxt->nbErrors++;
3527 }
3528 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3529 groups[j]->attrs);
3530 if (ret == 0) {
3531 if (ctxt->error != NULL)
3532 ctxt->error(ctxt->userData,
3533 "Attributes conflicts in interleave\n");
3534 ctxt->nbErrors++;
3535 }
3536 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003537 tmp = group->defs;
3538 if ((tmp != NULL) && (*tmp != NULL)) {
3539 while (*tmp != NULL) {
3540 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3541 res = xmlHashAddEntry2(partitions->triage,
3542 BAD_CAST "#text", NULL,
3543 (void *)(i + 1));
3544 if (res != 0)
3545 is_determinist = -1;
3546 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3547 ((*tmp)->name != NULL)) {
3548 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3549 res = xmlHashAddEntry2(partitions->triage,
3550 (*tmp)->name, NULL,
3551 (void *)(i + 1));
3552 else
3553 res = xmlHashAddEntry2(partitions->triage,
3554 (*tmp)->name, (*tmp)->ns,
3555 (void *)(i + 1));
3556 if (res != 0)
3557 is_determinist = -1;
3558 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3559 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3560 res = xmlHashAddEntry2(partitions->triage,
3561 BAD_CAST "#any", NULL,
3562 (void *)(i + 1));
3563 else
3564 res = xmlHashAddEntry2(partitions->triage,
3565 BAD_CAST "#any", (*tmp)->ns,
3566 (void *)(i + 1));
3567 if ((*tmp)->nameClass != NULL)
3568 is_determinist = 2;
3569 if (res != 0)
3570 is_determinist = -1;
3571 } else {
3572 is_determinist = -1;
3573 }
3574 tmp++;
3575 }
3576 } else {
3577 is_determinist = 0;
3578 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003579 }
3580 partitions->groups = groups;
3581
3582 /*
3583 * and save the partition list back in the def
3584 */
3585 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003586 if (is_mixed != 0)
3587 def->flags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003588 if (is_determinist == 1)
3589 partitions->flags = IS_DETERMINIST;
3590 if (is_determinist == 2)
3591 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003592 return;
3593
3594error:
3595 if (ctxt->error != NULL)
3596 ctxt->error(ctxt->userData,
3597 "Out of memory in interleave computation\n");
3598 ctxt->nbErrors++;
3599 if (groups != NULL) {
3600 for (i = 0;i < nbgroups;i++)
3601 if (groups[i] != NULL) {
3602 if (groups[i]->defs != NULL)
3603 xmlFree(groups[i]->defs);
3604 xmlFree(groups[i]);
3605 }
3606 xmlFree(groups);
3607 }
3608 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003609}
3610
3611/**
3612 * xmlRelaxNGParseInterleave:
3613 * @ctxt: a Relax-NG parser context
3614 * @node: the data node.
3615 *
3616 * parse the content of a RelaxNG interleave node.
3617 *
3618 * Returns the definition pointer or NULL in case of error
3619 */
3620static xmlRelaxNGDefinePtr
3621xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3622 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003623 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003624 xmlNodePtr child;
3625
Daniel Veillardfd573f12003-03-16 17:52:32 +00003626 def = xmlRelaxNGNewDefine(ctxt, node);
3627 if (def == NULL) {
3628 return(NULL);
3629 }
3630 def->type = XML_RELAXNG_INTERLEAVE;
3631
3632 if (ctxt->interleaves == NULL)
3633 ctxt->interleaves = xmlHashCreate(10);
3634 if (ctxt->interleaves == NULL) {
3635 if (ctxt->error != NULL)
3636 ctxt->error(ctxt->userData,
3637 "Failed to create interleaves hash table\n");
3638 ctxt->nbErrors++;
3639 } else {
3640 char name[32];
3641
3642 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3643 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3644 if (ctxt->error != NULL)
3645 ctxt->error(ctxt->userData,
3646 "Failed to add %s to hash table\n", name);
3647 ctxt->nbErrors++;
3648 }
3649 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003650 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003651 if (child == NULL) {
3652 if (ctxt->error != NULL)
3653 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3654 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003655 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003656 while (child != NULL) {
3657 if (IS_RELAXNG(child, "element")) {
3658 cur = xmlRelaxNGParseElement(ctxt, child);
3659 } else {
3660 cur = xmlRelaxNGParsePattern(ctxt, child);
3661 }
3662 if (cur != NULL) {
3663 cur->parent = def;
3664 if (last == NULL) {
3665 def->content = last = cur;
3666 } else {
3667 last->next = cur;
3668 last = cur;
3669 }
3670 }
3671 child = child->next;
3672 }
3673
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003674 return(def);
3675}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003676
3677/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003678 * xmlRelaxNGParseInclude:
3679 * @ctxt: a Relax-NG parser context
3680 * @node: the include node
3681 *
3682 * Integrate the content of an include node in the current grammar
3683 *
3684 * Returns 0 in case of success or -1 in case of error
3685 */
3686static int
3687xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3688 xmlRelaxNGIncludePtr incl;
3689 xmlNodePtr root;
3690 int ret = 0, tmp;
3691
3692 incl = node->_private;
3693 if (incl == NULL) {
3694 if (ctxt->error != NULL)
3695 ctxt->error(ctxt->userData,
3696 "Include node has no data\n");
3697 ctxt->nbErrors++;
3698 return(-1);
3699 }
3700 root = xmlDocGetRootElement(incl->doc);
3701 if (root == NULL) {
3702 if (ctxt->error != NULL)
3703 ctxt->error(ctxt->userData,
3704 "Include document is empty\n");
3705 ctxt->nbErrors++;
3706 return(-1);
3707 }
3708 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3709 if (ctxt->error != NULL)
3710 ctxt->error(ctxt->userData,
3711 "Include document root is not a grammar\n");
3712 ctxt->nbErrors++;
3713 return(-1);
3714 }
3715
3716 /*
3717 * Merge the definition from both the include and the internal list
3718 */
3719 if (root->children != NULL) {
3720 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3721 if (tmp != 0)
3722 ret = -1;
3723 }
3724 if (node->children != NULL) {
3725 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3726 if (tmp != 0)
3727 ret = -1;
3728 }
3729 return(ret);
3730}
3731
3732/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003733 * xmlRelaxNGParseDefine:
3734 * @ctxt: a Relax-NG parser context
3735 * @node: the define node
3736 *
3737 * parse the content of a RelaxNG define element node.
3738 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003739 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003740 */
3741static int
3742xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3743 xmlChar *name;
3744 int ret = 0, tmp;
3745 xmlRelaxNGDefinePtr def;
3746 const xmlChar *olddefine;
3747
3748 name = xmlGetProp(node, BAD_CAST "name");
3749 if (name == NULL) {
3750 if (ctxt->error != NULL)
3751 ctxt->error(ctxt->userData,
3752 "define has no name\n");
3753 ctxt->nbErrors++;
3754 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003755 xmlRelaxNGNormExtSpace(name);
3756 if (xmlValidateNCName(name, 0)) {
3757 if (ctxt->error != NULL)
3758 ctxt->error(ctxt->userData,
3759 "define name '%s' is not an NCName\n",
3760 name);
3761 ctxt->nbErrors++;
3762 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003763 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003764 if (def == NULL) {
3765 xmlFree(name);
3766 return(-1);
3767 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003768 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003769 def->name = name;
3770 if (node->children == NULL) {
3771 if (ctxt->error != NULL)
3772 ctxt->error(ctxt->userData,
3773 "define has no children\n");
3774 ctxt->nbErrors++;
3775 } else {
3776 olddefine = ctxt->define;
3777 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003778 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003779 ctxt->define = olddefine;
3780 }
3781 if (ctxt->grammar->defs == NULL)
3782 ctxt->grammar->defs = xmlHashCreate(10);
3783 if (ctxt->grammar->defs == NULL) {
3784 if (ctxt->error != NULL)
3785 ctxt->error(ctxt->userData,
3786 "Could not create definition hash\n");
3787 ctxt->nbErrors++;
3788 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003789 } else {
3790 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3791 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003792 xmlRelaxNGDefinePtr prev;
3793
3794 prev = xmlHashLookup(ctxt->grammar->defs, name);
3795 if (prev == NULL) {
3796 if (ctxt->error != NULL)
3797 ctxt->error(ctxt->userData,
3798 "Internal error on define aggregation of %s\n",
3799 name);
3800 ctxt->nbErrors++;
3801 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003802 } else {
3803 while (prev->nextHash != NULL)
3804 prev = prev->nextHash;
3805 prev->nextHash = def;
3806 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003807 }
3808 }
3809 }
3810 return(ret);
3811}
3812
3813/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003814 * xmlRelaxNGProcessExternalRef:
3815 * @ctxt: the parser context
3816 * @node: the externlRef node
3817 *
3818 * Process and compile an externlRef node
3819 *
3820 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3821 */
3822static xmlRelaxNGDefinePtr
3823xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3824 xmlRelaxNGDocumentPtr docu;
3825 xmlNodePtr root, tmp;
3826 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003827 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003828 xmlRelaxNGDefinePtr def;
3829
3830 docu = node->_private;
3831 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003832 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003833 if (def == NULL)
3834 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003835 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003836
3837 if (docu->content == NULL) {
3838 /*
3839 * Then do the parsing for good
3840 */
3841 root = xmlDocGetRootElement(docu->doc);
3842 if (root == NULL) {
3843 if (ctxt->error != NULL)
3844 ctxt->error(ctxt->userData,
3845 "xmlRelaxNGParse: %s is empty\n",
3846 ctxt->URL);
3847 ctxt->nbErrors++;
3848 return (NULL);
3849 }
3850 /*
3851 * ns transmission rules
3852 */
3853 ns = xmlGetProp(root, BAD_CAST "ns");
3854 if (ns == NULL) {
3855 tmp = node;
3856 while ((tmp != NULL) &&
3857 (tmp->type == XML_ELEMENT_NODE)) {
3858 ns = xmlGetProp(tmp, BAD_CAST "ns");
3859 if (ns != NULL) {
3860 break;
3861 }
3862 tmp = tmp->parent;
3863 }
3864 if (ns != NULL) {
3865 xmlSetProp(root, BAD_CAST "ns", ns);
3866 newNs = 1;
3867 xmlFree(ns);
3868 }
3869 } else {
3870 xmlFree(ns);
3871 }
3872
3873 /*
3874 * Parsing to get a precompiled schemas.
3875 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003876 oldflags = ctxt->flags;
3877 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003878 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003879 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003880 if ((docu->schema != NULL) &&
3881 (docu->schema->topgrammar != NULL)) {
3882 docu->content = docu->schema->topgrammar->start;
3883 }
3884
3885 /*
3886 * the externalRef may be reused in a different ns context
3887 */
3888 if (newNs == 1) {
3889 xmlUnsetProp(root, BAD_CAST "ns");
3890 }
3891 }
3892 def->content = docu->content;
3893 } else {
3894 def = NULL;
3895 }
3896 return(def);
3897}
3898
3899/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003900 * xmlRelaxNGParsePattern:
3901 * @ctxt: a Relax-NG parser context
3902 * @node: the pattern node.
3903 *
3904 * parse the content of a RelaxNG pattern node.
3905 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003906 * Returns the definition pointer or NULL in case of error or if no
3907 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003908 */
3909static xmlRelaxNGDefinePtr
3910xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3911 xmlRelaxNGDefinePtr def = NULL;
3912
Daniel Veillardd2298792003-02-14 16:54:11 +00003913 if (node == NULL) {
3914 return(NULL);
3915 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003916 if (IS_RELAXNG(node, "element")) {
3917 def = xmlRelaxNGParseElement(ctxt, node);
3918 } else if (IS_RELAXNG(node, "attribute")) {
3919 def = xmlRelaxNGParseAttribute(ctxt, node);
3920 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003921 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003922 if (def == NULL)
3923 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003924 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00003925 if (node->children != NULL) {
3926 if (ctxt->error != NULL)
3927 ctxt->error(ctxt->userData, "empty: had a child node\n");
3928 ctxt->nbErrors++;
3929 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003930 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003931 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003932 if (def == NULL)
3933 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003934 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003935 if (node->children != NULL) {
3936 if (ctxt->error != NULL)
3937 ctxt->error(ctxt->userData, "text: had a child node\n");
3938 ctxt->nbErrors++;
3939 }
3940 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003941 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003942 if (def == NULL)
3943 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003944 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003945 if (node->children == NULL) {
3946 if (ctxt->error != NULL)
3947 ctxt->error(ctxt->userData,
3948 "Element %s is empty\n", node->name);
3949 ctxt->nbErrors++;
3950 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003951 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00003952 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003953 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003954 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003955 if (def == NULL)
3956 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003957 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003958 if (node->children == NULL) {
3959 if (ctxt->error != NULL)
3960 ctxt->error(ctxt->userData,
3961 "Element %s is empty\n", node->name);
3962 ctxt->nbErrors++;
3963 } else {
3964 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3965 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003966 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003967 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003968 if (def == NULL)
3969 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003970 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003971 if (node->children == NULL) {
3972 if (ctxt->error != NULL)
3973 ctxt->error(ctxt->userData,
3974 "Element %s is empty\n", node->name);
3975 ctxt->nbErrors++;
3976 } else {
3977 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3978 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003979 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003980 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003981 if (def == NULL)
3982 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003983 def->type = XML_RELAXNG_CHOICE;
3984 if (node->children == NULL) {
3985 if (ctxt->error != NULL)
3986 ctxt->error(ctxt->userData,
3987 "Element %s is empty\n", node->name);
3988 ctxt->nbErrors++;
3989 } else {
3990 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3991 }
3992 } else if (IS_RELAXNG(node, "group")) {
3993 def = xmlRelaxNGNewDefine(ctxt, node);
3994 if (def == NULL)
3995 return(NULL);
3996 def->type = XML_RELAXNG_GROUP;
3997 if (node->children == NULL) {
3998 if (ctxt->error != NULL)
3999 ctxt->error(ctxt->userData,
4000 "Element %s is empty\n", node->name);
4001 ctxt->nbErrors++;
4002 } else {
4003 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4004 }
4005 } else if (IS_RELAXNG(node, "ref")) {
4006 def = xmlRelaxNGNewDefine(ctxt, node);
4007 if (def == NULL)
4008 return(NULL);
4009 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004010 def->name = xmlGetProp(node, BAD_CAST "name");
4011 if (def->name == NULL) {
4012 if (ctxt->error != NULL)
4013 ctxt->error(ctxt->userData,
4014 "ref has no name\n");
4015 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004016 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004017 xmlRelaxNGNormExtSpace(def->name);
4018 if (xmlValidateNCName(def->name, 0)) {
4019 if (ctxt->error != NULL)
4020 ctxt->error(ctxt->userData,
4021 "ref name '%s' is not an NCName\n",
4022 def->name);
4023 ctxt->nbErrors++;
4024 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004025 }
4026 if (node->children != NULL) {
4027 if (ctxt->error != NULL)
4028 ctxt->error(ctxt->userData,
4029 "ref is not empty\n");
4030 ctxt->nbErrors++;
4031 }
4032 if (ctxt->grammar->refs == NULL)
4033 ctxt->grammar->refs = xmlHashCreate(10);
4034 if (ctxt->grammar->refs == NULL) {
4035 if (ctxt->error != NULL)
4036 ctxt->error(ctxt->userData,
4037 "Could not create references hash\n");
4038 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004039 def = NULL;
4040 } else {
4041 int tmp;
4042
4043 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4044 if (tmp < 0) {
4045 xmlRelaxNGDefinePtr prev;
4046
4047 prev = (xmlRelaxNGDefinePtr)
4048 xmlHashLookup(ctxt->grammar->refs, def->name);
4049 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004050 if (def->name != NULL) {
4051 if (ctxt->error != NULL)
4052 ctxt->error(ctxt->userData,
4053 "Error refs definitions '%s'\n",
4054 def->name);
4055 } else {
4056 if (ctxt->error != NULL)
4057 ctxt->error(ctxt->userData,
4058 "Error refs definitions\n");
4059 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004060 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004061 def = NULL;
4062 } else {
4063 def->nextHash = prev->nextHash;
4064 prev->nextHash = def;
4065 }
4066 }
4067 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004068 } else if (IS_RELAXNG(node, "data")) {
4069 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004070 } else if (IS_RELAXNG(node, "value")) {
4071 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004072 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004073 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004074 if (def == NULL)
4075 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004076 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004077 if (node->children == NULL) {
4078 if (ctxt->error != NULL)
4079 ctxt->error(ctxt->userData,
4080 "Element %s is empty\n", node->name);
4081 ctxt->nbErrors++;
4082 } else {
4083 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4084 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004085 } else if (IS_RELAXNG(node, "interleave")) {
4086 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004087 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004088 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004089 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004090 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004091 if (def == NULL)
4092 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004093 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004094 if (node->children != NULL) {
4095 if (ctxt->error != NULL)
4096 ctxt->error(ctxt->userData,
4097 "xmlRelaxNGParse: notAllowed element is not empty\n");
4098 ctxt->nbErrors++;
4099 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004100 } else if (IS_RELAXNG(node, "grammar")) {
4101 xmlRelaxNGGrammarPtr grammar, old;
4102 xmlRelaxNGGrammarPtr oldparent;
4103
Daniel Veillardc482e262003-02-26 14:48:48 +00004104#ifdef DEBUG_GRAMMAR
4105 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4106#endif
4107
Daniel Veillard419a7682003-02-03 23:22:49 +00004108 oldparent = ctxt->parentgrammar;
4109 old = ctxt->grammar;
4110 ctxt->parentgrammar = old;
4111 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4112 if (old != NULL) {
4113 ctxt->grammar = old;
4114 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004115#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004116 if (grammar != NULL) {
4117 grammar->next = old->next;
4118 old->next = grammar;
4119 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004120#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004121 }
4122 if (grammar != NULL)
4123 def = grammar->start;
4124 else
4125 def = NULL;
4126 } else if (IS_RELAXNG(node, "parentRef")) {
4127 if (ctxt->parentgrammar == NULL) {
4128 if (ctxt->error != NULL)
4129 ctxt->error(ctxt->userData,
4130 "Use of parentRef without a parent grammar\n");
4131 ctxt->nbErrors++;
4132 return(NULL);
4133 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004134 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004135 if (def == NULL)
4136 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004137 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004138 def->name = xmlGetProp(node, BAD_CAST "name");
4139 if (def->name == NULL) {
4140 if (ctxt->error != NULL)
4141 ctxt->error(ctxt->userData,
4142 "parentRef has no name\n");
4143 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004144 } else {
4145 xmlRelaxNGNormExtSpace(def->name);
4146 if (xmlValidateNCName(def->name, 0)) {
4147 if (ctxt->error != NULL)
4148 ctxt->error(ctxt->userData,
4149 "parentRef name '%s' is not an NCName\n",
4150 def->name);
4151 ctxt->nbErrors++;
4152 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004153 }
4154 if (node->children != NULL) {
4155 if (ctxt->error != NULL)
4156 ctxt->error(ctxt->userData,
4157 "parentRef is not empty\n");
4158 ctxt->nbErrors++;
4159 }
4160 if (ctxt->parentgrammar->refs == NULL)
4161 ctxt->parentgrammar->refs = xmlHashCreate(10);
4162 if (ctxt->parentgrammar->refs == NULL) {
4163 if (ctxt->error != NULL)
4164 ctxt->error(ctxt->userData,
4165 "Could not create references hash\n");
4166 ctxt->nbErrors++;
4167 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004168 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004169 int tmp;
4170
4171 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4172 if (tmp < 0) {
4173 xmlRelaxNGDefinePtr prev;
4174
4175 prev = (xmlRelaxNGDefinePtr)
4176 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4177 if (prev == NULL) {
4178 if (ctxt->error != NULL)
4179 ctxt->error(ctxt->userData,
4180 "Internal error parentRef definitions '%s'\n",
4181 def->name);
4182 ctxt->nbErrors++;
4183 def = NULL;
4184 } else {
4185 def->nextHash = prev->nextHash;
4186 prev->nextHash = def;
4187 }
4188 }
4189 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004190 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004191 if (node->children == NULL) {
4192 if (ctxt->error != NULL)
4193 ctxt->error(ctxt->userData,
4194 "Mixed is empty\n");
4195 ctxt->nbErrors++;
4196 def = NULL;
4197 } else {
4198 def = xmlRelaxNGParseInterleave(ctxt, node);
4199 if (def != NULL) {
4200 xmlRelaxNGDefinePtr tmp;
4201
4202 if ((def->content != NULL) && (def->content->next != NULL)) {
4203 tmp = xmlRelaxNGNewDefine(ctxt, node);
4204 if (tmp != NULL) {
4205 tmp->type = XML_RELAXNG_GROUP;
4206 tmp->content = def->content;
4207 def->content = tmp;
4208 }
4209 }
4210
4211 tmp = xmlRelaxNGNewDefine(ctxt, node);
4212 if (tmp == NULL)
4213 return(def);
4214 tmp->type = XML_RELAXNG_TEXT;
4215 tmp->next = def->content;
4216 def->content = tmp;
4217 }
4218 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004219 } else {
4220 if (ctxt->error != NULL)
4221 ctxt->error(ctxt->userData,
4222 "Unexpected node %s is not a pattern\n",
4223 node->name);
4224 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004225 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004226 }
4227 return(def);
4228}
4229
4230/**
4231 * xmlRelaxNGParseAttribute:
4232 * @ctxt: a Relax-NG parser context
4233 * @node: the element node
4234 *
4235 * parse the content of a RelaxNG attribute node.
4236 *
4237 * Returns the definition pointer or NULL in case of error.
4238 */
4239static xmlRelaxNGDefinePtr
4240xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004241 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004242 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004243 int old_flags;
4244
Daniel Veillardfd573f12003-03-16 17:52:32 +00004245 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004246 if (ret == NULL)
4247 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004248 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004249 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004250 child = node->children;
4251 if (child == NULL) {
4252 if (ctxt->error != NULL)
4253 ctxt->error(ctxt->userData,
4254 "xmlRelaxNGParseattribute: attribute has no children\n");
4255 ctxt->nbErrors++;
4256 return(ret);
4257 }
4258 old_flags = ctxt->flags;
4259 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004260 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4261 if (cur != NULL)
4262 child = child->next;
4263
Daniel Veillardd2298792003-02-14 16:54:11 +00004264 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004265 cur = xmlRelaxNGParsePattern(ctxt, child);
4266 if (cur != NULL) {
4267 switch (cur->type) {
4268 case XML_RELAXNG_EMPTY:
4269 case XML_RELAXNG_NOT_ALLOWED:
4270 case XML_RELAXNG_TEXT:
4271 case XML_RELAXNG_ELEMENT:
4272 case XML_RELAXNG_DATATYPE:
4273 case XML_RELAXNG_VALUE:
4274 case XML_RELAXNG_LIST:
4275 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004276 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004277 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004278 case XML_RELAXNG_DEF:
4279 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004280 case XML_RELAXNG_ZEROORMORE:
4281 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004282 case XML_RELAXNG_CHOICE:
4283 case XML_RELAXNG_GROUP:
4284 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004285 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004286 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004287 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004288 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004289 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004290 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004291 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004292 if (ctxt->error != NULL)
4293 ctxt->error(ctxt->userData,
4294 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004295 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004296 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004297 case XML_RELAXNG_NOOP:
4298 TODO
4299 if (ctxt->error != NULL)
4300 ctxt->error(ctxt->userData,
4301 "Internal error, noop found\n");
4302 ctxt->nbErrors++;
4303 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004304 }
4305 }
4306 child = child->next;
4307 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004308 if (child != NULL) {
4309 if (ctxt->error != NULL)
4310 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4311 ctxt->nbErrors++;
4312 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004313 ctxt->flags = old_flags;
4314 return(ret);
4315}
4316
4317/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004318 * xmlRelaxNGParseExceptNameClass:
4319 * @ctxt: a Relax-NG parser context
4320 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004321 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004322 *
4323 * parse the content of a RelaxNG nameClass node.
4324 *
4325 * Returns the definition pointer or NULL in case of error.
4326 */
4327static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004328xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4329 xmlNodePtr node, int attr) {
4330 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4331 xmlNodePtr child;
4332
Daniel Veillardd2298792003-02-14 16:54:11 +00004333 if (!IS_RELAXNG(node, "except")) {
4334 if (ctxt->error != NULL)
4335 ctxt->error(ctxt->userData,
4336 "Expecting an except node\n");
4337 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004338 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004339 }
4340 if (node->next != NULL) {
4341 if (ctxt->error != NULL)
4342 ctxt->error(ctxt->userData,
4343 "exceptNameClass allows only a single except node\n");
4344 ctxt->nbErrors++;
4345 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004346 if (node->children == NULL) {
4347 if (ctxt->error != NULL)
4348 ctxt->error(ctxt->userData,
4349 "except has no content\n");
4350 ctxt->nbErrors++;
4351 return(NULL);
4352 }
4353
Daniel Veillardfd573f12003-03-16 17:52:32 +00004354 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004355 if (ret == NULL)
4356 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004357 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004358 child = node->children;
4359 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004360 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004361 if (cur == NULL)
4362 break;
4363 if (attr)
4364 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004365 else
4366 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004367
Daniel Veillard419a7682003-02-03 23:22:49 +00004368 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004369 if (last == NULL) {
4370 ret->content = cur;
4371 } else {
4372 last->next = cur;
4373 }
4374 last = cur;
4375 }
4376 child = child->next;
4377 }
4378
4379 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004380}
4381
4382/**
4383 * xmlRelaxNGParseNameClass:
4384 * @ctxt: a Relax-NG parser context
4385 * @node: the nameClass node
4386 * @def: the current definition
4387 *
4388 * parse the content of a RelaxNG nameClass node.
4389 *
4390 * Returns the definition pointer or NULL in case of error.
4391 */
4392static xmlRelaxNGDefinePtr
4393xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4394 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004395 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004396 xmlChar *val;
4397
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004398 ret = def;
4399 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4400 (IS_RELAXNG(node, "nsName"))) {
4401 if ((def->type != XML_RELAXNG_ELEMENT) &&
4402 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004403 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004404 if (ret == NULL)
4405 return(NULL);
4406 ret->parent = def;
4407 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4408 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004409 else
4410 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004411 }
4412 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004413 if (IS_RELAXNG(node, "name")) {
4414 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004415 xmlRelaxNGNormExtSpace(val);
4416 if (xmlValidateNCName(val, 0)) {
4417 if (ctxt->error != NULL) {
4418 if (node->parent != NULL)
4419 ctxt->error(ctxt->userData,
4420 "Element %s name '%s' is not an NCName\n",
4421 node->parent->name, val);
4422 else
4423 ctxt->error(ctxt->userData,
4424 "name '%s' is not an NCName\n",
4425 val);
4426 }
4427 ctxt->nbErrors++;
4428 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004429 ret->name = val;
4430 val = xmlGetProp(node, BAD_CAST "ns");
4431 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004432 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4433 (val != NULL) &&
4434 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4435 ctxt->error(ctxt->userData,
4436 "Attribute with namespace '%s' is not allowed\n",
4437 val);
4438 ctxt->nbErrors++;
4439 }
4440 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4441 (val != NULL) &&
4442 (val[0] == 0) &&
4443 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4444 ctxt->error(ctxt->userData,
4445 "Attribute with QName 'xmlns' is not allowed\n",
4446 val);
4447 ctxt->nbErrors++;
4448 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004449 } else if (IS_RELAXNG(node, "anyName")) {
4450 ret->name = NULL;
4451 ret->ns = NULL;
4452 if (node->children != NULL) {
4453 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004454 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4455 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004456 }
4457 } else if (IS_RELAXNG(node, "nsName")) {
4458 ret->name = NULL;
4459 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4460 if (ret->ns == NULL) {
4461 if (ctxt->error != NULL)
4462 ctxt->error(ctxt->userData,
4463 "nsName has no ns attribute\n");
4464 ctxt->nbErrors++;
4465 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004466 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4467 (ret->ns != NULL) &&
4468 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4469 ctxt->error(ctxt->userData,
4470 "Attribute with namespace '%s' is not allowed\n",
4471 ret->ns);
4472 ctxt->nbErrors++;
4473 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004474 if (node->children != NULL) {
4475 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004476 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4477 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004478 }
4479 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 xmlNodePtr child;
4481 xmlRelaxNGDefinePtr last = NULL;
4482
4483 ret = xmlRelaxNGNewDefine(ctxt, node);
4484 if (ret == NULL)
4485 return(NULL);
4486 ret->parent = def;
4487 ret->type = XML_RELAXNG_CHOICE;
4488
Daniel Veillardd2298792003-02-14 16:54:11 +00004489 if (node->children == NULL) {
4490 if (ctxt->error != NULL)
4491 ctxt->error(ctxt->userData,
4492 "Element choice is empty\n");
4493 ctxt->nbErrors++;
4494 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004495
4496 child = node->children;
4497 while (child != NULL) {
4498 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4499 if (tmp != NULL) {
4500 if (last == NULL) {
4501 last = ret->nameClass = tmp;
4502 } else {
4503 last->next = tmp;
4504 last = tmp;
4505 }
4506 }
4507 child = child->next;
4508 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004509 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004510 } else {
4511 if (ctxt->error != NULL)
4512 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004513 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004514 node->name);
4515 ctxt->nbErrors++;
4516 return(NULL);
4517 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004518 if (ret != def) {
4519 if (def->nameClass == NULL) {
4520 def->nameClass = ret;
4521 } else {
4522 tmp = def->nameClass;
4523 while (tmp->next != NULL) {
4524 tmp = tmp->next;
4525 }
4526 tmp->next = ret;
4527 }
4528 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004529 return(ret);
4530}
4531
4532/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004533 * xmlRelaxNGParseElement:
4534 * @ctxt: a Relax-NG parser context
4535 * @node: the element node
4536 *
4537 * parse the content of a RelaxNG element node.
4538 *
4539 * Returns the definition pointer or NULL in case of error.
4540 */
4541static xmlRelaxNGDefinePtr
4542xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4543 xmlRelaxNGDefinePtr ret, cur, last;
4544 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004545 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004546
Daniel Veillardfd573f12003-03-16 17:52:32 +00004547 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004548 if (ret == NULL)
4549 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004550 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004551 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004552 child = node->children;
4553 if (child == NULL) {
4554 if (ctxt->error != NULL)
4555 ctxt->error(ctxt->userData,
4556 "xmlRelaxNGParseElement: element has no children\n");
4557 ctxt->nbErrors++;
4558 return(ret);
4559 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004560 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4561 if (cur != NULL)
4562 child = child->next;
4563
Daniel Veillard6eadf632003-01-23 18:29:16 +00004564 if (child == NULL) {
4565 if (ctxt->error != NULL)
4566 ctxt->error(ctxt->userData,
4567 "xmlRelaxNGParseElement: element has no content\n");
4568 ctxt->nbErrors++;
4569 return(ret);
4570 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004571 olddefine = ctxt->define;
4572 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004573 last = NULL;
4574 while (child != NULL) {
4575 cur = xmlRelaxNGParsePattern(ctxt, child);
4576 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004577 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004578 switch (cur->type) {
4579 case XML_RELAXNG_EMPTY:
4580 case XML_RELAXNG_NOT_ALLOWED:
4581 case XML_RELAXNG_TEXT:
4582 case XML_RELAXNG_ELEMENT:
4583 case XML_RELAXNG_DATATYPE:
4584 case XML_RELAXNG_VALUE:
4585 case XML_RELAXNG_LIST:
4586 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004587 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004588 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004589 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004590 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004591 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004592 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004593 case XML_RELAXNG_CHOICE:
4594 case XML_RELAXNG_GROUP:
4595 case XML_RELAXNG_INTERLEAVE:
4596 if (last == NULL) {
4597 ret->content = last = cur;
4598 } else {
4599 if ((last->type == XML_RELAXNG_ELEMENT) &&
4600 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004601 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004602 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004603 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004604 ret->content->content = last;
4605 } else {
4606 ret->content = last;
4607 }
4608 }
4609 last->next = cur;
4610 last = cur;
4611 }
4612 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004613 case XML_RELAXNG_ATTRIBUTE:
4614 cur->next = ret->attrs;
4615 ret->attrs = cur;
4616 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004617 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004618 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004619 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004620 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004621 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004622 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004623 case XML_RELAXNG_NOOP:
4624 TODO
4625 if (ctxt->error != NULL)
4626 ctxt->error(ctxt->userData,
4627 "Internal error, noop found\n");
4628 ctxt->nbErrors++;
4629 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004630 }
4631 }
4632 child = child->next;
4633 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004634 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004635 return(ret);
4636}
4637
4638/**
4639 * xmlRelaxNGParsePatterns:
4640 * @ctxt: a Relax-NG parser context
4641 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004642 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004643 *
4644 * parse the content of a RelaxNG start node.
4645 *
4646 * Returns the definition pointer or NULL in case of error.
4647 */
4648static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004649xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4650 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004651 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004652
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004653 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004654 while (nodes != NULL) {
4655 if (IS_RELAXNG(nodes, "element")) {
4656 cur = xmlRelaxNGParseElement(ctxt, nodes);
4657 if (def == NULL) {
4658 def = last = cur;
4659 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004660 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4661 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004662 def = xmlRelaxNGNewDefine(ctxt, nodes);
4663 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004664 def->content = last;
4665 }
4666 last->next = cur;
4667 last = cur;
4668 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004669 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004670 } else {
4671 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004672 if (cur != NULL) {
4673 if (def == NULL) {
4674 def = last = cur;
4675 } else {
4676 last->next = cur;
4677 last = cur;
4678 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004679 }
4680 }
4681 nodes = nodes->next;
4682 }
4683 return(def);
4684}
4685
4686/**
4687 * xmlRelaxNGParseStart:
4688 * @ctxt: a Relax-NG parser context
4689 * @nodes: start children nodes
4690 *
4691 * parse the content of a RelaxNG start node.
4692 *
4693 * Returns 0 in case of success, -1 in case of error
4694 */
4695static int
4696xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4697 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004698 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004699
Daniel Veillardd2298792003-02-14 16:54:11 +00004700 if (nodes == NULL) {
4701 if (ctxt->error != NULL)
4702 ctxt->error(ctxt->userData,
4703 "start has no children\n");
4704 ctxt->nbErrors++;
4705 return(-1);
4706 }
4707 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004708 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004709 if (def == NULL)
4710 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004711 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004712 if (nodes->children != NULL) {
4713 if (ctxt->error != NULL)
4714 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004715 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004716 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004717 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004718 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004719 if (def == NULL)
4720 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004721 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004722 if (nodes->children != NULL) {
4723 if (ctxt->error != NULL)
4724 ctxt->error(ctxt->userData,
4725 "element notAllowed is not empty\n");
4726 ctxt->nbErrors++;
4727 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004728 } else {
4729 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004730 }
4731 if (ctxt->grammar->start != NULL) {
4732 last = ctxt->grammar->start;
4733 while (last->next != NULL)
4734 last = last->next;
4735 last->next = def;
4736 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004737 ctxt->grammar->start = def;
4738 }
4739 nodes = nodes->next;
4740 if (nodes != NULL) {
4741 if (ctxt->error != NULL)
4742 ctxt->error(ctxt->userData,
4743 "start more than one children\n");
4744 ctxt->nbErrors++;
4745 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004746 }
4747 return(ret);
4748}
4749
4750/**
4751 * xmlRelaxNGParseGrammarContent:
4752 * @ctxt: a Relax-NG parser context
4753 * @nodes: grammar children nodes
4754 *
4755 * parse the content of a RelaxNG grammar node.
4756 *
4757 * Returns 0 in case of success, -1 in case of error
4758 */
4759static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004760xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004761{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004762 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004763
4764 if (nodes == NULL) {
4765 if (ctxt->error != NULL)
4766 ctxt->error(ctxt->userData,
4767 "grammar has no children\n");
4768 ctxt->nbErrors++;
4769 return(-1);
4770 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004771 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004772 if (IS_RELAXNG(nodes, "start")) {
4773 if (nodes->children == NULL) {
4774 if (ctxt->error != NULL)
4775 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004776 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004777 ctxt->nbErrors++;
4778 } else {
4779 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4780 if (tmp != 0)
4781 ret = -1;
4782 }
4783 } else if (IS_RELAXNG(nodes, "define")) {
4784 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4785 if (tmp != 0)
4786 ret = -1;
4787 } else if (IS_RELAXNG(nodes, "include")) {
4788 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4789 if (tmp != 0)
4790 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004791 } else {
4792 if (ctxt->error != NULL)
4793 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004794 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004795 ctxt->nbErrors++;
4796 ret = -1;
4797 }
4798 nodes = nodes->next;
4799 }
4800 return (ret);
4801}
4802
4803/**
4804 * xmlRelaxNGCheckReference:
4805 * @ref: the ref
4806 * @ctxt: a Relax-NG parser context
4807 * @name: the name associated to the defines
4808 *
4809 * Applies the 4.17. combine attribute rule for all the define
4810 * element of a given grammar using the same name.
4811 */
4812static void
4813xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4814 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4815 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004816 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004817
4818 grammar = ctxt->grammar;
4819 if (grammar == NULL) {
4820 if (ctxt->error != NULL)
4821 ctxt->error(ctxt->userData,
4822 "Internal error: no grammar in CheckReference %s\n",
4823 name);
4824 ctxt->nbErrors++;
4825 return;
4826 }
4827 if (ref->content != NULL) {
4828 if (ctxt->error != NULL)
4829 ctxt->error(ctxt->userData,
4830 "Internal error: reference has content in CheckReference %s\n",
4831 name);
4832 ctxt->nbErrors++;
4833 return;
4834 }
4835 if (grammar->defs != NULL) {
4836 def = xmlHashLookup(grammar->defs, name);
4837 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004838 cur = ref;
4839 while (cur != NULL) {
4840 cur->content = def;
4841 cur = cur->nextHash;
4842 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004843 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004844 if (ctxt->error != NULL)
4845 ctxt->error(ctxt->userData,
4846 "Reference %s has no matching definition\n",
4847 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004848 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004849 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004850 } else {
4851 if (ctxt->error != NULL)
4852 ctxt->error(ctxt->userData,
4853 "Reference %s has no matching definition\n",
4854 name);
4855 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004856 }
4857 /*
4858 * TODO: make a closure and verify there is no loop !
4859 */
4860}
4861
4862/**
4863 * xmlRelaxNGCheckCombine:
4864 * @define: the define(s) list
4865 * @ctxt: a Relax-NG parser context
4866 * @name: the name associated to the defines
4867 *
4868 * Applies the 4.17. combine attribute rule for all the define
4869 * element of a given grammar using the same name.
4870 */
4871static void
4872xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4873 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4874 xmlChar *combine;
4875 int choiceOrInterleave = -1;
4876 int missing = 0;
4877 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4878
4879 if (define->nextHash == NULL)
4880 return;
4881 cur = define;
4882 while (cur != NULL) {
4883 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4884 if (combine != NULL) {
4885 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4886 if (choiceOrInterleave == -1)
4887 choiceOrInterleave = 1;
4888 else if (choiceOrInterleave == 0) {
4889 if (ctxt->error != NULL)
4890 ctxt->error(ctxt->userData,
4891 "Defines for %s use both 'choice' and 'interleave'\n",
4892 name);
4893 ctxt->nbErrors++;
4894 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004895 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004896 if (choiceOrInterleave == -1)
4897 choiceOrInterleave = 0;
4898 else if (choiceOrInterleave == 1) {
4899 if (ctxt->error != NULL)
4900 ctxt->error(ctxt->userData,
4901 "Defines for %s use both 'choice' and 'interleave'\n",
4902 name);
4903 ctxt->nbErrors++;
4904 }
4905 } else {
4906 if (ctxt->error != NULL)
4907 ctxt->error(ctxt->userData,
4908 "Defines for %s use unknown combine value '%s''\n",
4909 name, combine);
4910 ctxt->nbErrors++;
4911 }
4912 xmlFree(combine);
4913 } else {
4914 if (missing == 0)
4915 missing = 1;
4916 else {
4917 if (ctxt->error != NULL)
4918 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004919 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004920 name);
4921 ctxt->nbErrors++;
4922 }
4923 }
4924
4925 cur = cur->nextHash;
4926 }
4927#ifdef DEBUG
4928 xmlGenericError(xmlGenericErrorContext,
4929 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4930 name, choiceOrInterleave);
4931#endif
4932 if (choiceOrInterleave == -1)
4933 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004934 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004935 if (cur == NULL)
4936 return;
4937 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004938 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004939 else
4940 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004941 tmp = define;
4942 last = NULL;
4943 while (tmp != NULL) {
4944 if (tmp->content != NULL) {
4945 if (tmp->content->next != NULL) {
4946 /*
4947 * we need first to create a wrapper.
4948 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00004949 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004950 if (tmp2 == NULL)
4951 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004952 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004953 tmp2->content = tmp->content;
4954 } else {
4955 tmp2 = tmp->content;
4956 }
4957 if (last == NULL) {
4958 cur->content = tmp2;
4959 } else {
4960 last->next = tmp2;
4961 }
4962 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004963 }
Daniel Veillard952379b2003-03-17 15:37:12 +00004964 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004965 tmp = tmp->nextHash;
4966 }
4967 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004968 if (choiceOrInterleave == 0) {
4969 if (ctxt->interleaves == NULL)
4970 ctxt->interleaves = xmlHashCreate(10);
4971 if (ctxt->interleaves == NULL) {
4972 if (ctxt->error != NULL)
4973 ctxt->error(ctxt->userData,
4974 "Failed to create interleaves hash table\n");
4975 ctxt->nbErrors++;
4976 } else {
4977 char tmpname[32];
4978
4979 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4980 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4981 if (ctxt->error != NULL)
4982 ctxt->error(ctxt->userData,
4983 "Failed to add %s to hash table\n", tmpname);
4984 ctxt->nbErrors++;
4985 }
4986 }
4987 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004988}
4989
4990/**
4991 * xmlRelaxNGCombineStart:
4992 * @ctxt: a Relax-NG parser context
4993 * @grammar: the grammar
4994 *
4995 * Applies the 4.17. combine rule for all the start
4996 * element of a given grammar.
4997 */
4998static void
4999xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5000 xmlRelaxNGGrammarPtr grammar) {
5001 xmlRelaxNGDefinePtr starts;
5002 xmlChar *combine;
5003 int choiceOrInterleave = -1;
5004 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005005 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005006
Daniel Veillard2df2de22003-02-17 23:34:33 +00005007 starts = grammar->start;
5008 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005009 return;
5010 cur = starts;
5011 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005012 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5013 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5014 combine = NULL;
5015 if (ctxt->error != NULL)
5016 ctxt->error(ctxt->userData,
5017 "Internal error: start element not found\n");
5018 ctxt->nbErrors++;
5019 } else {
5020 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5021 }
5022
Daniel Veillard6eadf632003-01-23 18:29:16 +00005023 if (combine != NULL) {
5024 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5025 if (choiceOrInterleave == -1)
5026 choiceOrInterleave = 1;
5027 else if (choiceOrInterleave == 0) {
5028 if (ctxt->error != NULL)
5029 ctxt->error(ctxt->userData,
5030 "<start> use both 'choice' and 'interleave'\n");
5031 ctxt->nbErrors++;
5032 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005033 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005034 if (choiceOrInterleave == -1)
5035 choiceOrInterleave = 0;
5036 else if (choiceOrInterleave == 1) {
5037 if (ctxt->error != NULL)
5038 ctxt->error(ctxt->userData,
5039 "<start> use both 'choice' and 'interleave'\n");
5040 ctxt->nbErrors++;
5041 }
5042 } else {
5043 if (ctxt->error != NULL)
5044 ctxt->error(ctxt->userData,
5045 "<start> uses unknown combine value '%s''\n", combine);
5046 ctxt->nbErrors++;
5047 }
5048 xmlFree(combine);
5049 } else {
5050 if (missing == 0)
5051 missing = 1;
5052 else {
5053 if (ctxt->error != NULL)
5054 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005055 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005056 ctxt->nbErrors++;
5057 }
5058 }
5059
Daniel Veillard2df2de22003-02-17 23:34:33 +00005060 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005061 }
5062#ifdef DEBUG
5063 xmlGenericError(xmlGenericErrorContext,
5064 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5065 choiceOrInterleave);
5066#endif
5067 if (choiceOrInterleave == -1)
5068 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005069 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005070 if (cur == NULL)
5071 return;
5072 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005073 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005074 else
5075 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005076 cur->content = grammar->start;
5077 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005078 if (choiceOrInterleave == 0) {
5079 if (ctxt->interleaves == NULL)
5080 ctxt->interleaves = xmlHashCreate(10);
5081 if (ctxt->interleaves == NULL) {
5082 if (ctxt->error != NULL)
5083 ctxt->error(ctxt->userData,
5084 "Failed to create interleaves hash table\n");
5085 ctxt->nbErrors++;
5086 } else {
5087 char tmpname[32];
5088
5089 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5090 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5091 if (ctxt->error != NULL)
5092 ctxt->error(ctxt->userData,
5093 "Failed to add %s to hash table\n", tmpname);
5094 ctxt->nbErrors++;
5095 }
5096 }
5097 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005098}
5099
5100/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005101 * xmlRelaxNGCheckCycles:
5102 * @ctxt: a Relax-NG parser context
5103 * @nodes: grammar children nodes
5104 * @depth: the counter
5105 *
5106 * Check for cycles.
5107 *
5108 * Returns 0 if check passed, and -1 in case of error
5109 */
5110static int
5111xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5112 xmlRelaxNGDefinePtr cur, int depth) {
5113 int ret = 0;
5114
5115 while ((ret == 0) && (cur != NULL)) {
5116 if ((cur->type == XML_RELAXNG_REF) ||
5117 (cur->type == XML_RELAXNG_PARENTREF)) {
5118 if (cur->depth == -1) {
5119 cur->depth = depth;
5120 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5121 cur->depth = -2;
5122 } else if (depth == cur->depth) {
5123 if (ctxt->error != NULL)
5124 ctxt->error(ctxt->userData,
5125 "Detected a cycle in %s references\n", cur->name);
5126 ctxt->nbErrors++;
5127 return(-1);
5128 }
5129 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5130 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5131 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005132 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005133 }
5134 cur = cur->next;
5135 }
5136 return(ret);
5137}
5138
5139/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005140 * xmlRelaxNGTryUnlink:
5141 * @ctxt: a Relax-NG parser context
5142 * @cur: the definition to unlink
5143 * @parent: the parent definition
5144 * @prev: the previous sibling definition
5145 *
5146 * Try to unlink a definition. If not possble make it a NOOP
5147 *
5148 * Returns the new prev definition
5149 */
5150static xmlRelaxNGDefinePtr
5151xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5152 xmlRelaxNGDefinePtr cur,
5153 xmlRelaxNGDefinePtr parent,
5154 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005155 if (prev != NULL) {
5156 prev->next = cur->next;
5157 } else {
5158 if (parent != NULL) {
5159 if (parent->content == cur)
5160 parent->content = cur->next;
5161 else if (parent->attrs == cur)
5162 parent->attrs = cur->next;
5163 else if (parent->nameClass == cur)
5164 parent->nameClass = cur->next;
5165 } else {
5166 cur->type = XML_RELAXNG_NOOP;
5167 prev = cur;
5168 }
5169 }
5170 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005171}
5172
5173/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005174 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005175 * @ctxt: a Relax-NG parser context
5176 * @nodes: grammar children nodes
5177 *
5178 * Check for simplification of empty and notAllowed
5179 */
5180static void
5181xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5182 xmlRelaxNGDefinePtr cur,
5183 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005184 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005185
Daniel Veillardfd573f12003-03-16 17:52:32 +00005186 while (cur != NULL) {
5187 if ((cur->type == XML_RELAXNG_REF) ||
5188 (cur->type == XML_RELAXNG_PARENTREF)) {
5189 if (cur->depth != -3) {
5190 cur->depth = -3;
5191 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005192 }
5193 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005194 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005195 if ((parent != NULL) &&
5196 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5197 (parent->type == XML_RELAXNG_LIST) ||
5198 (parent->type == XML_RELAXNG_GROUP) ||
5199 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005200 (parent->type == XML_RELAXNG_ONEORMORE) ||
5201 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005202 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005203 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005204 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005205 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005206 (parent->type == XML_RELAXNG_CHOICE)) {
5207 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5208 } else
5209 prev = cur;
5210 } else if (cur->type == XML_RELAXNG_EMPTY){
5211 cur->parent = parent;
5212 if ((parent != NULL) &&
5213 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5214 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005215 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005216 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005217 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005218 if ((parent != NULL) &&
5219 ((parent->type == XML_RELAXNG_GROUP) ||
5220 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5221 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5222 } else
5223 prev = cur;
5224 } else {
5225 cur->parent = parent;
5226 if (cur->content != NULL)
5227 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5228 if (cur->attrs != NULL)
5229 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5230 if (cur->nameClass != NULL)
5231 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5232 /*
5233 * This may result in a simplification
5234 */
5235 if ((cur->type == XML_RELAXNG_GROUP) ||
5236 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5237 if (cur->content == NULL)
5238 cur->type = XML_RELAXNG_EMPTY;
5239 else if (cur->content->next == NULL) {
5240 if ((parent == NULL) && (prev == NULL)) {
5241 cur->type = XML_RELAXNG_NOOP;
5242 } else if (prev == NULL) {
5243 parent->content = cur->content;
5244 cur->content->next = cur->next;
5245 cur = cur->content;
5246 } else {
5247 cur->content->next = cur->next;
5248 prev->next = cur->content;
5249 cur = cur->content;
5250 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005251 }
5252 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005253 /*
5254 * the current node may have been transformed back
5255 */
5256 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5257 (cur->content != NULL) &&
5258 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5259 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5260 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5261 if ((parent != NULL) &&
5262 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5263 (parent->type == XML_RELAXNG_LIST) ||
5264 (parent->type == XML_RELAXNG_GROUP) ||
5265 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5266 (parent->type == XML_RELAXNG_ONEORMORE) ||
5267 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5268 parent->type = XML_RELAXNG_NOT_ALLOWED;
5269 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005270 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005271 if ((parent != NULL) &&
5272 (parent->type == XML_RELAXNG_CHOICE)) {
5273 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5274 } else
5275 prev = cur;
5276 } else if (cur->type == XML_RELAXNG_EMPTY){
5277 if ((parent != NULL) &&
5278 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5279 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5280 parent->type = XML_RELAXNG_EMPTY;
5281 break;
5282 }
5283 if ((parent != NULL) &&
5284 ((parent->type == XML_RELAXNG_GROUP) ||
5285 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5286 (parent->type == XML_RELAXNG_CHOICE))) {
5287 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5288 } else
5289 prev = cur;
5290 } else {
5291 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005292 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005293 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005294 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005295 }
5296}
5297
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005298/**
5299 * xmlRelaxNGGroupContentType:
5300 * @ct1: the first content type
5301 * @ct2: the second content type
5302 *
5303 * Try to group 2 content types
5304 *
5305 * Returns the content type
5306 */
5307static xmlRelaxNGContentType
5308xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5309 xmlRelaxNGContentType ct2) {
5310 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5311 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5312 return(XML_RELAXNG_CONTENT_ERROR);
5313 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5314 return(ct2);
5315 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5316 return(ct1);
5317 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5318 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5319 return(XML_RELAXNG_CONTENT_COMPLEX);
5320 return(XML_RELAXNG_CONTENT_ERROR);
5321}
5322
5323/**
5324 * xmlRelaxNGMaxContentType:
5325 * @ct1: the first content type
5326 * @ct2: the second content type
5327 *
5328 * Compute the max content-type
5329 *
5330 * Returns the content type
5331 */
5332static xmlRelaxNGContentType
5333xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5334 xmlRelaxNGContentType ct2) {
5335 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5336 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5337 return(XML_RELAXNG_CONTENT_ERROR);
5338 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5339 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5340 return(XML_RELAXNG_CONTENT_SIMPLE);
5341 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5342 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5343 return(XML_RELAXNG_CONTENT_COMPLEX);
5344 return(XML_RELAXNG_CONTENT_EMPTY);
5345}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005346
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005347/**
5348 * xmlRelaxNGCheckRules:
5349 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005350 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005351 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005352 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005353 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005354 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005355 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005356 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005357 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005358static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005359xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5360 xmlRelaxNGDefinePtr cur, int flags,
5361 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005362 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005363 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005364
Daniel Veillardfd573f12003-03-16 17:52:32 +00005365 while (cur != NULL) {
5366 ret = XML_RELAXNG_CONTENT_EMPTY;
5367 if ((cur->type == XML_RELAXNG_REF) ||
5368 (cur->type == XML_RELAXNG_PARENTREF)) {
5369 if (flags & XML_RELAXNG_IN_LIST) {
5370 if (ctxt->error != NULL)
5371 ctxt->error(ctxt->userData,
5372 "Found forbidden pattern list//ref\n");
5373 ctxt->nbErrors++;
5374 }
5375 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5376 if (ctxt->error != NULL)
5377 ctxt->error(ctxt->userData,
5378 "Found forbidden pattern data/except//ref\n");
5379 ctxt->nbErrors++;
5380 }
5381 if (cur->depth > -4) {
5382 cur->depth = -4;
5383 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5384 flags, cur->type);
5385 cur->depth = ret - 15 ;
5386 } else if (cur->depth == -4) {
5387 ret = XML_RELAXNG_CONTENT_COMPLEX;
5388 } else {
5389 ret = (xmlRelaxNGContentType) cur->depth + 15;
5390 }
5391 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5392 /*
5393 * The 7.3 Attribute derivation rule for groups is plugged there
5394 */
5395 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5396 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5397 if (ctxt->error != NULL)
5398 ctxt->error(ctxt->userData,
5399 "Found forbidden pattern data/except//element(ref)\n");
5400 ctxt->nbErrors++;
5401 }
5402 if (flags & XML_RELAXNG_IN_LIST) {
5403 if (ctxt->error != NULL)
5404 ctxt->error(ctxt->userData,
5405 "Found forbidden pattern list//element(ref)\n");
5406 ctxt->nbErrors++;
5407 }
5408 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5409 if (ctxt->error != NULL)
5410 ctxt->error(ctxt->userData,
5411 "Found forbidden pattern attribute//element(ref)\n");
5412 ctxt->nbErrors++;
5413 }
5414 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5415 if (ctxt->error != NULL)
5416 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005417 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005418 ctxt->nbErrors++;
5419 }
5420 /*
5421 * reset since in the simple form elements are only child
5422 * of grammar/define
5423 */
5424 nflags = 0;
5425 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5426 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5427 if (ctxt->error != NULL)
5428 ctxt->error(ctxt->userData,
5429 "Element %s attributes have a content type error\n",
5430 cur->name);
5431 ctxt->nbErrors++;
5432 }
5433 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5434 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5435 if (ctxt->error != NULL)
5436 ctxt->error(ctxt->userData,
5437 "Element %s has a content type error\n",
5438 cur->name);
5439 ctxt->nbErrors++;
5440 } else {
5441 ret = XML_RELAXNG_CONTENT_COMPLEX;
5442 }
5443 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5444 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5445 if (ctxt->error != NULL)
5446 ctxt->error(ctxt->userData,
5447 "Found forbidden pattern attribute//attribute\n");
5448 ctxt->nbErrors++;
5449 }
5450 if (flags & XML_RELAXNG_IN_LIST) {
5451 if (ctxt->error != NULL)
5452 ctxt->error(ctxt->userData,
5453 "Found forbidden pattern list//attribute\n");
5454 ctxt->nbErrors++;
5455 }
5456 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5457 if (ctxt->error != NULL)
5458 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005459 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005460 ctxt->nbErrors++;
5461 }
5462 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5463 if (ctxt->error != NULL)
5464 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005465 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005466 ctxt->nbErrors++;
5467 }
5468 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5469 if (ctxt->error != NULL)
5470 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005471 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005472 ctxt->nbErrors++;
5473 }
5474 if (flags & XML_RELAXNG_IN_START) {
5475 if (ctxt->error != NULL)
5476 ctxt->error(ctxt->userData,
5477 "Found forbidden pattern start//attribute\n");
5478 ctxt->nbErrors++;
5479 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005480 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5481 if (cur->ns == NULL) {
5482 if (ctxt->error != NULL)
5483 ctxt->error(ctxt->userData,
5484 "Found anyName attribute without oneOrMore ancestor\n");
5485 ctxt->nbErrors++;
5486 } else {
5487 if (ctxt->error != NULL)
5488 ctxt->error(ctxt->userData,
5489 "Found nsName attribute without oneOrMore ancestor\n");
5490 ctxt->nbErrors++;
5491 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005492 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005493 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5494 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5495 ret = XML_RELAXNG_CONTENT_EMPTY;
5496 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5497 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5498 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5499 if (ctxt->error != NULL)
5500 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005501 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005502 ctxt->nbErrors++;
5503 }
5504 if (flags & XML_RELAXNG_IN_START) {
5505 if (ctxt->error != NULL)
5506 ctxt->error(ctxt->userData,
5507 "Found forbidden pattern start//oneOrMore\n");
5508 ctxt->nbErrors++;
5509 }
5510 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5511 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5512 ret = xmlRelaxNGGroupContentType(ret, ret);
5513 } else if (cur->type == XML_RELAXNG_LIST) {
5514 if (flags & XML_RELAXNG_IN_LIST) {
5515 if (ctxt->error != NULL)
5516 ctxt->error(ctxt->userData,
5517 "Found forbidden pattern list//list\n");
5518 ctxt->nbErrors++;
5519 }
5520 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5521 if (ctxt->error != NULL)
5522 ctxt->error(ctxt->userData,
5523 "Found forbidden pattern data/except//list\n");
5524 ctxt->nbErrors++;
5525 }
5526 if (flags & XML_RELAXNG_IN_START) {
5527 if (ctxt->error != NULL)
5528 ctxt->error(ctxt->userData,
5529 "Found forbidden pattern start//list\n");
5530 ctxt->nbErrors++;
5531 }
5532 nflags = flags | XML_RELAXNG_IN_LIST;
5533 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5534 } else if (cur->type == XML_RELAXNG_GROUP) {
5535 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5536 if (ctxt->error != NULL)
5537 ctxt->error(ctxt->userData,
5538 "Found forbidden pattern data/except//group\n");
5539 ctxt->nbErrors++;
5540 }
5541 if (flags & XML_RELAXNG_IN_START) {
5542 if (ctxt->error != NULL)
5543 ctxt->error(ctxt->userData,
5544 "Found forbidden pattern start//group\n");
5545 ctxt->nbErrors++;
5546 }
5547 if (flags & XML_RELAXNG_IN_ONEORMORE)
5548 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5549 else
5550 nflags = flags;
5551 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5552 /*
5553 * The 7.3 Attribute derivation rule for groups is plugged there
5554 */
5555 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5556 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5557 if (flags & XML_RELAXNG_IN_LIST) {
5558 if (ctxt->error != NULL)
5559 ctxt->error(ctxt->userData,
5560 "Found forbidden pattern list//interleave\n");
5561 ctxt->nbErrors++;
5562 }
5563 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5564 if (ctxt->error != NULL)
5565 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005566 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005567 ctxt->nbErrors++;
5568 }
5569 if (flags & XML_RELAXNG_IN_START) {
5570 if (ctxt->error != NULL)
5571 ctxt->error(ctxt->userData,
5572 "Found forbidden pattern start//interleave\n");
5573 ctxt->nbErrors++;
5574 }
5575 if (flags & XML_RELAXNG_IN_ONEORMORE)
5576 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5577 else
5578 nflags = flags;
5579 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5580 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5581 if ((cur->parent != NULL) &&
5582 (cur->parent->type == XML_RELAXNG_DATATYPE))
5583 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5584 else
5585 nflags = flags;
5586 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5587 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5588 if (flags & XML_RELAXNG_IN_START) {
5589 if (ctxt->error != NULL)
5590 ctxt->error(ctxt->userData,
5591 "Found forbidden pattern start//data\n");
5592 ctxt->nbErrors++;
5593 }
5594 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5595 ret = XML_RELAXNG_CONTENT_SIMPLE;
5596 } else if (cur->type == XML_RELAXNG_VALUE) {
5597 if (flags & XML_RELAXNG_IN_START) {
5598 if (ctxt->error != NULL)
5599 ctxt->error(ctxt->userData,
5600 "Found forbidden pattern start//value\n");
5601 ctxt->nbErrors++;
5602 }
5603 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5604 ret = XML_RELAXNG_CONTENT_SIMPLE;
5605 } else if (cur->type == XML_RELAXNG_TEXT) {
5606 if (flags & XML_RELAXNG_IN_LIST) {
5607 if (ctxt->error != NULL)
5608 ctxt->error(ctxt->userData,
5609 "Found forbidden pattern list//text\n");
5610 ctxt->nbErrors++;
5611 }
5612 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5613 if (ctxt->error != NULL)
5614 ctxt->error(ctxt->userData,
5615 "Found forbidden pattern data/except//text\n");
5616 ctxt->nbErrors++;
5617 }
5618 if (flags & XML_RELAXNG_IN_START) {
5619 if (ctxt->error != NULL)
5620 ctxt->error(ctxt->userData,
5621 "Found forbidden pattern start//text\n");
5622 ctxt->nbErrors++;
5623 }
5624 ret = XML_RELAXNG_CONTENT_COMPLEX;
5625 } else if (cur->type == XML_RELAXNG_EMPTY) {
5626 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5627 if (ctxt->error != NULL)
5628 ctxt->error(ctxt->userData,
5629 "Found forbidden pattern data/except//empty\n");
5630 ctxt->nbErrors++;
5631 }
5632 if (flags & XML_RELAXNG_IN_START) {
5633 if (ctxt->error != NULL)
5634 ctxt->error(ctxt->userData,
5635 "Found forbidden pattern start//empty\n");
5636 ctxt->nbErrors++;
5637 }
5638 ret = XML_RELAXNG_CONTENT_EMPTY;
5639 } else if (cur->type == XML_RELAXNG_CHOICE) {
5640 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5641 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5642 } else {
5643 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5644 }
5645 cur = cur->next;
5646 if (ptype == XML_RELAXNG_GROUP) {
5647 val = xmlRelaxNGGroupContentType(val, ret);
5648 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5649 tmp = xmlRelaxNGGroupContentType(val, ret);
5650 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5651 tmp = xmlRelaxNGMaxContentType(val, ret);
5652 } else if (ptype == XML_RELAXNG_CHOICE) {
5653 val = xmlRelaxNGMaxContentType(val, ret);
5654 } else if (ptype == XML_RELAXNG_LIST) {
5655 val = XML_RELAXNG_CONTENT_SIMPLE;
5656 } else if (ptype == XML_RELAXNG_EXCEPT) {
5657 if (ret == XML_RELAXNG_CONTENT_ERROR)
5658 val = XML_RELAXNG_CONTENT_ERROR;
5659 else
5660 val = XML_RELAXNG_CONTENT_SIMPLE;
5661 } else {
5662 val = xmlRelaxNGGroupContentType(val, ret);
5663 }
5664
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005665 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005666 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005667}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005668
5669/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005670 * xmlRelaxNGParseGrammar:
5671 * @ctxt: a Relax-NG parser context
5672 * @nodes: grammar children nodes
5673 *
5674 * parse a Relax-NG <grammar> node
5675 *
5676 * Returns the internal xmlRelaxNGGrammarPtr built or
5677 * NULL in case of error
5678 */
5679static xmlRelaxNGGrammarPtr
5680xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5681 xmlRelaxNGGrammarPtr ret, tmp, old;
5682
Daniel Veillardc482e262003-02-26 14:48:48 +00005683#ifdef DEBUG_GRAMMAR
5684 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5685#endif
5686
Daniel Veillard6eadf632003-01-23 18:29:16 +00005687 ret = xmlRelaxNGNewGrammar(ctxt);
5688 if (ret == NULL)
5689 return(NULL);
5690
5691 /*
5692 * Link the new grammar in the tree
5693 */
5694 ret->parent = ctxt->grammar;
5695 if (ctxt->grammar != NULL) {
5696 tmp = ctxt->grammar->children;
5697 if (tmp == NULL) {
5698 ctxt->grammar->children = ret;
5699 } else {
5700 while (tmp->next != NULL)
5701 tmp = tmp->next;
5702 tmp->next = ret;
5703 }
5704 }
5705
5706 old = ctxt->grammar;
5707 ctxt->grammar = ret;
5708 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5709 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005710 if (ctxt->grammar == NULL) {
5711 if (ctxt->error != NULL)
5712 ctxt->error(ctxt->userData,
5713 "Failed to parse <grammar> content\n");
5714 ctxt->nbErrors++;
5715 } else if (ctxt->grammar->start == NULL) {
5716 if (ctxt->error != NULL)
5717 ctxt->error(ctxt->userData,
5718 "Element <grammar> has no <start>\n");
5719 ctxt->nbErrors++;
5720 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005721
5722 /*
5723 * Apply 4.17 mergingd rules to defines and starts
5724 */
5725 xmlRelaxNGCombineStart(ctxt, ret);
5726 if (ret->defs != NULL) {
5727 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5728 ctxt);
5729 }
5730
5731 /*
5732 * link together defines and refs in this grammar
5733 */
5734 if (ret->refs != NULL) {
5735 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5736 ctxt);
5737 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005738
Daniel Veillard6eadf632003-01-23 18:29:16 +00005739 ctxt->grammar = old;
5740 return(ret);
5741}
5742
5743/**
5744 * xmlRelaxNGParseDocument:
5745 * @ctxt: a Relax-NG parser context
5746 * @node: the root node of the RelaxNG schema
5747 *
5748 * parse a Relax-NG definition resource and build an internal
5749 * xmlRelaxNG struture which can be used to validate instances.
5750 *
5751 * Returns the internal XML RelaxNG structure built or
5752 * NULL in case of error
5753 */
5754static xmlRelaxNGPtr
5755xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5756 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005757 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005758 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005759
5760 if ((ctxt == NULL) || (node == NULL))
5761 return (NULL);
5762
5763 schema = xmlRelaxNGNewRelaxNG(ctxt);
5764 if (schema == NULL)
5765 return(NULL);
5766
Daniel Veillard276be4a2003-01-24 01:03:34 +00005767 olddefine = ctxt->define;
5768 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005769 if (IS_RELAXNG(node, "grammar")) {
5770 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5771 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005772 xmlRelaxNGGrammarPtr tmp, ret;
5773
5774 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005775 if (schema->topgrammar == NULL) {
5776 return(schema);
5777 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005778 /*
5779 * Link the new grammar in the tree
5780 */
5781 ret->parent = ctxt->grammar;
5782 if (ctxt->grammar != NULL) {
5783 tmp = ctxt->grammar->children;
5784 if (tmp == NULL) {
5785 ctxt->grammar->children = ret;
5786 } else {
5787 while (tmp->next != NULL)
5788 tmp = tmp->next;
5789 tmp->next = ret;
5790 }
5791 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005792 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005793 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005794 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005795 if (old != NULL)
5796 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005797 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005798 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005799 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005800 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005801 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005802 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5803 while ((schema->topgrammar->start != NULL) &&
5804 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5805 (schema->topgrammar->start->next != NULL))
5806 schema->topgrammar->start = schema->topgrammar->start->content;
5807 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5808 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005809 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005810 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005811
5812#ifdef DEBUG
5813 if (schema == NULL)
5814 xmlGenericError(xmlGenericErrorContext,
5815 "xmlRelaxNGParseDocument() failed\n");
5816#endif
5817
5818 return (schema);
5819}
5820
5821/************************************************************************
5822 * *
5823 * Reading RelaxNGs *
5824 * *
5825 ************************************************************************/
5826
5827/**
5828 * xmlRelaxNGNewParserCtxt:
5829 * @URL: the location of the schema
5830 *
5831 * Create an XML RelaxNGs parse context for that file/resource expected
5832 * to contain an XML RelaxNGs file.
5833 *
5834 * Returns the parser context or NULL in case of error
5835 */
5836xmlRelaxNGParserCtxtPtr
5837xmlRelaxNGNewParserCtxt(const char *URL) {
5838 xmlRelaxNGParserCtxtPtr ret;
5839
5840 if (URL == NULL)
5841 return(NULL);
5842
5843 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5844 if (ret == NULL) {
5845 xmlGenericError(xmlGenericErrorContext,
5846 "Failed to allocate new schama parser context for %s\n", URL);
5847 return (NULL);
5848 }
5849 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5850 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005851 ret->error = xmlGenericError;
5852 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005853 return (ret);
5854}
5855
5856/**
5857 * xmlRelaxNGNewMemParserCtxt:
5858 * @buffer: a pointer to a char array containing the schemas
5859 * @size: the size of the array
5860 *
5861 * Create an XML RelaxNGs parse context for that memory buffer expected
5862 * to contain an XML RelaxNGs file.
5863 *
5864 * Returns the parser context or NULL in case of error
5865 */
5866xmlRelaxNGParserCtxtPtr
5867xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5868 xmlRelaxNGParserCtxtPtr ret;
5869
5870 if ((buffer == NULL) || (size <= 0))
5871 return(NULL);
5872
5873 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5874 if (ret == NULL) {
5875 xmlGenericError(xmlGenericErrorContext,
5876 "Failed to allocate new schama parser context\n");
5877 return (NULL);
5878 }
5879 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5880 ret->buffer = buffer;
5881 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005882 ret->error = xmlGenericError;
5883 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005884 return (ret);
5885}
5886
5887/**
5888 * xmlRelaxNGFreeParserCtxt:
5889 * @ctxt: the schema parser context
5890 *
5891 * Free the resources associated to the schema parser context
5892 */
5893void
5894xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5895 if (ctxt == NULL)
5896 return;
5897 if (ctxt->URL != NULL)
5898 xmlFree(ctxt->URL);
5899 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005900 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005901 if (ctxt->interleaves != NULL)
5902 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005903 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005904 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005905 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005906 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005907 if (ctxt->docTab != NULL)
5908 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005909 if (ctxt->incTab != NULL)
5910 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005911 if (ctxt->defTab != NULL) {
5912 int i;
5913
5914 for (i = 0;i < ctxt->defNr;i++)
5915 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5916 xmlFree(ctxt->defTab);
5917 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005918 xmlFree(ctxt);
5919}
5920
Daniel Veillard6eadf632003-01-23 18:29:16 +00005921/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005922 * xmlRelaxNGNormExtSpace:
5923 * @value: a value
5924 *
5925 * Removes the leading and ending spaces of the value
5926 * The string is modified "in situ"
5927 */
5928static void
5929xmlRelaxNGNormExtSpace(xmlChar *value) {
5930 xmlChar *start = value;
5931 xmlChar *cur = value;
5932 if (value == NULL)
5933 return;
5934
5935 while (IS_BLANK(*cur)) cur++;
5936 if (cur == start) {
5937 do {
5938 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5939 if (*cur == 0)
5940 return;
5941 start = cur;
5942 while (IS_BLANK(*cur)) cur++;
5943 if (*cur == 0) {
5944 *start = 0;
5945 return;
5946 }
5947 } while (1);
5948 } else {
5949 do {
5950 while ((*cur != 0) && (!IS_BLANK(*cur)))
5951 *start++ = *cur++;
5952 if (*cur == 0) {
5953 *start = 0;
5954 return;
5955 }
5956 /* don't try to normalize the inner spaces */
5957 while (IS_BLANK(*cur)) cur++;
5958 *start++ = *cur++;
5959 if (*cur == 0) {
5960 *start = 0;
5961 return;
5962 }
5963 } while (1);
5964 }
5965}
5966
5967/**
5968 * xmlRelaxNGCheckAttributes:
5969 * @ctxt: a Relax-NG parser context
5970 * @node: a Relax-NG node
5971 *
5972 * Check all the attributes on the given node
5973 */
5974static void
5975xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5976 xmlAttrPtr cur, next;
5977
5978 cur = node->properties;
5979 while (cur != NULL) {
5980 next = cur->next;
5981 if ((cur->ns == NULL) ||
5982 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
5983 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5984 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
5985 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
5986 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
5987 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00005988 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00005989 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5990 if (ctxt->error != NULL)
5991 ctxt->error(ctxt->userData,
5992 "Attribute %s is not allowed on %s\n",
5993 cur->name, node->name);
5994 ctxt->nbErrors++;
5995 }
5996 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
5997 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
5998 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
5999 if (ctxt->error != NULL)
6000 ctxt->error(ctxt->userData,
6001 "Attribute %s is not allowed on %s\n",
6002 cur->name, node->name);
6003 ctxt->nbErrors++;
6004 }
6005 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6006 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6007 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6008 if (ctxt->error != NULL)
6009 ctxt->error(ctxt->userData,
6010 "Attribute %s is not allowed on %s\n",
6011 cur->name, node->name);
6012 ctxt->nbErrors++;
6013 }
6014 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6015 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6016 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6017 if (ctxt->error != NULL)
6018 ctxt->error(ctxt->userData,
6019 "Attribute %s is not allowed on %s\n",
6020 cur->name, node->name);
6021 ctxt->nbErrors++;
6022 }
6023 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6024 xmlChar *val;
6025 xmlURIPtr uri;
6026
6027 val = xmlNodeListGetString(node->doc, cur->children, 1);
6028 if (val != NULL) {
6029 if (val[0] != 0) {
6030 uri = xmlParseURI((const char *) val);
6031 if (uri == NULL) {
6032 if (ctxt->error != NULL)
6033 ctxt->error(ctxt->userData,
6034 "Attribute %s contains invalid URI %s\n",
6035 cur->name, val);
6036 ctxt->nbErrors++;
6037 } else {
6038 if (uri->scheme == NULL) {
6039 if (ctxt->error != NULL)
6040 ctxt->error(ctxt->userData,
6041 "Attribute %s URI %s is not absolute\n",
6042 cur->name, val);
6043 ctxt->nbErrors++;
6044 }
6045 if (uri->fragment != NULL) {
6046 if (ctxt->error != NULL)
6047 ctxt->error(ctxt->userData,
6048 "Attribute %s URI %s has a fragment ID\n",
6049 cur->name, val);
6050 ctxt->nbErrors++;
6051 }
6052 xmlFreeURI(uri);
6053 }
6054 }
6055 xmlFree(val);
6056 }
6057 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6058 if (ctxt->error != NULL)
6059 ctxt->error(ctxt->userData,
6060 "Unknown attribute %s on %s\n",
6061 cur->name, node->name);
6062 ctxt->nbErrors++;
6063 }
6064 }
6065 cur = next;
6066 }
6067}
6068
6069/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006070 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006071 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006072 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006073 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006074 * Cleanup the subtree from unwanted nodes for parsing, resolve
6075 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006076 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006077static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006078xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006079 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006080
Daniel Veillard6eadf632003-01-23 18:29:16 +00006081 delete = NULL;
6082 cur = root;
6083 while (cur != NULL) {
6084 if (delete != NULL) {
6085 xmlUnlinkNode(delete);
6086 xmlFreeNode(delete);
6087 delete = NULL;
6088 }
6089 if (cur->type == XML_ELEMENT_NODE) {
6090 /*
6091 * Simplification 4.1. Annotations
6092 */
6093 if ((cur->ns == NULL) ||
6094 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006095 if ((cur->parent != NULL) &&
6096 (cur->parent->type == XML_ELEMENT_NODE) &&
6097 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6098 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6099 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6100 if (ctxt->error != NULL)
6101 ctxt->error(ctxt->userData,
6102 "element %s doesn't allow foreign elements\n",
6103 cur->parent->name);
6104 ctxt->nbErrors++;
6105 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006106 delete = cur;
6107 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006108 } else {
6109 xmlRelaxNGCleanupAttributes(ctxt, cur);
6110 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6111 xmlChar *href, *ns, *base, *URL;
6112 xmlRelaxNGDocumentPtr docu;
6113 xmlNodePtr tmp;
6114
6115 ns = xmlGetProp(cur, BAD_CAST "ns");
6116 if (ns == NULL) {
6117 tmp = cur->parent;
6118 while ((tmp != NULL) &&
6119 (tmp->type == XML_ELEMENT_NODE)) {
6120 ns = xmlGetProp(tmp, BAD_CAST "ns");
6121 if (ns != NULL)
6122 break;
6123 tmp = tmp->parent;
6124 }
6125 }
6126 href = xmlGetProp(cur, BAD_CAST "href");
6127 if (href == NULL) {
6128 if (ctxt->error != NULL)
6129 ctxt->error(ctxt->userData,
6130 "xmlRelaxNGParse: externalRef has no href attribute\n");
6131 ctxt->nbErrors++;
6132 delete = cur;
6133 goto skip_children;
6134 }
6135 base = xmlNodeGetBase(cur->doc, cur);
6136 URL = xmlBuildURI(href, base);
6137 if (URL == NULL) {
6138 if (ctxt->error != NULL)
6139 ctxt->error(ctxt->userData,
6140 "Failed to compute URL for externalRef %s\n", href);
6141 ctxt->nbErrors++;
6142 if (href != NULL)
6143 xmlFree(href);
6144 if (base != NULL)
6145 xmlFree(base);
6146 delete = cur;
6147 goto skip_children;
6148 }
6149 if (href != NULL)
6150 xmlFree(href);
6151 if (base != NULL)
6152 xmlFree(base);
6153 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6154 if (docu == NULL) {
6155 if (ctxt->error != NULL)
6156 ctxt->error(ctxt->userData,
6157 "Failed to load externalRef %s\n", URL);
6158 ctxt->nbErrors++;
6159 xmlFree(URL);
6160 delete = cur;
6161 goto skip_children;
6162 }
6163 if (ns != NULL)
6164 xmlFree(ns);
6165 xmlFree(URL);
6166 cur->_private = docu;
6167 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6168 xmlChar *href, *ns, *base, *URL;
6169 xmlRelaxNGIncludePtr incl;
6170 xmlNodePtr tmp;
6171
6172 href = xmlGetProp(cur, BAD_CAST "href");
6173 if (href == NULL) {
6174 if (ctxt->error != NULL)
6175 ctxt->error(ctxt->userData,
6176 "xmlRelaxNGParse: include has no href attribute\n");
6177 ctxt->nbErrors++;
6178 delete = cur;
6179 goto skip_children;
6180 }
6181 base = xmlNodeGetBase(cur->doc, cur);
6182 URL = xmlBuildURI(href, base);
6183 if (URL == NULL) {
6184 if (ctxt->error != NULL)
6185 ctxt->error(ctxt->userData,
6186 "Failed to compute URL for include %s\n", href);
6187 ctxt->nbErrors++;
6188 if (href != NULL)
6189 xmlFree(href);
6190 if (base != NULL)
6191 xmlFree(base);
6192 delete = cur;
6193 goto skip_children;
6194 }
6195 if (href != NULL)
6196 xmlFree(href);
6197 if (base != NULL)
6198 xmlFree(base);
6199 ns = xmlGetProp(cur, BAD_CAST "ns");
6200 if (ns == NULL) {
6201 tmp = cur->parent;
6202 while ((tmp != NULL) &&
6203 (tmp->type == XML_ELEMENT_NODE)) {
6204 ns = xmlGetProp(tmp, BAD_CAST "ns");
6205 if (ns != NULL)
6206 break;
6207 tmp = tmp->parent;
6208 }
6209 }
6210 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6211 if (ns != NULL)
6212 xmlFree(ns);
6213 if (incl == NULL) {
6214 if (ctxt->error != NULL)
6215 ctxt->error(ctxt->userData,
6216 "Failed to load include %s\n", URL);
6217 ctxt->nbErrors++;
6218 xmlFree(URL);
6219 delete = cur;
6220 goto skip_children;
6221 }
6222 xmlFree(URL);
6223 cur->_private = incl;
6224 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6225 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6226 xmlChar *name, *ns;
6227 xmlNodePtr text = NULL;
6228
6229 /*
6230 * Simplification 4.8. name attribute of element
6231 * and attribute elements
6232 */
6233 name = xmlGetProp(cur, BAD_CAST "name");
6234 if (name != NULL) {
6235 if (cur->children == NULL) {
6236 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6237 name);
6238 } else {
6239 xmlNodePtr node;
6240 node = xmlNewNode(cur->ns, BAD_CAST "name");
6241 if (node != NULL) {
6242 xmlAddPrevSibling(cur->children, node);
6243 text = xmlNewText(name);
6244 xmlAddChild(node, text);
6245 text = node;
6246 }
6247 }
6248 if (text == NULL) {
6249 if (ctxt->error != NULL)
6250 ctxt->error(ctxt->userData,
6251 "Failed to create a name %s element\n", name);
6252 ctxt->nbErrors++;
6253 }
6254 xmlUnsetProp(cur, BAD_CAST "name");
6255 xmlFree(name);
6256 ns = xmlGetProp(cur, BAD_CAST "ns");
6257 if (ns != NULL) {
6258 if (text != NULL) {
6259 xmlSetProp(text, BAD_CAST "ns", ns);
6260 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6261 }
6262 xmlFree(ns);
6263 } else if (xmlStrEqual(cur->name,
6264 BAD_CAST "attribute")) {
6265 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6266 }
6267 }
6268 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6269 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6270 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6271 /*
6272 * Simplification 4.8. name attribute of element
6273 * and attribute elements
6274 */
6275 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6276 xmlNodePtr node;
6277 xmlChar *ns = NULL;
6278
6279 node = cur->parent;
6280 while ((node != NULL) &&
6281 (node->type == XML_ELEMENT_NODE)) {
6282 ns = xmlGetProp(node, BAD_CAST "ns");
6283 if (ns != NULL) {
6284 break;
6285 }
6286 node = node->parent;
6287 }
6288 if (ns == NULL) {
6289 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6290 } else {
6291 xmlSetProp(cur, BAD_CAST "ns", ns);
6292 xmlFree(ns);
6293 }
6294 }
6295 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6296 xmlChar *name, *local, *prefix;
6297
6298 /*
6299 * Simplification: 4.10. QNames
6300 */
6301 name = xmlNodeGetContent(cur);
6302 if (name != NULL) {
6303 local = xmlSplitQName2(name, &prefix);
6304 if (local != NULL) {
6305 xmlNsPtr ns;
6306
6307 ns = xmlSearchNs(cur->doc, cur, prefix);
6308 if (ns == NULL) {
6309 if (ctxt->error != NULL)
6310 ctxt->error(ctxt->userData,
6311 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6312 ctxt->nbErrors++;
6313 } else {
6314 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6315 xmlNodeSetContent(cur, local);
6316 }
6317 xmlFree(local);
6318 xmlFree(prefix);
6319 }
6320 xmlFree(name);
6321 }
6322 }
6323 /*
6324 * 4.16
6325 */
6326 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6327 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6328 if (ctxt->error != NULL)
6329 ctxt->error(ctxt->userData,
6330 "Found nsName/except//nsName forbidden construct\n");
6331 ctxt->nbErrors++;
6332 }
6333 }
6334 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6335 (cur != root)) {
6336 int oldflags = ctxt->flags;
6337
6338 /*
6339 * 4.16
6340 */
6341 if ((cur->parent != NULL) &&
6342 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6343 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6344 xmlRelaxNGCleanupTree(ctxt, cur);
6345 ctxt->flags = oldflags;
6346 goto skip_children;
6347 } else if ((cur->parent != NULL) &&
6348 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6349 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6350 xmlRelaxNGCleanupTree(ctxt, cur);
6351 ctxt->flags = oldflags;
6352 goto skip_children;
6353 }
6354 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6355 /*
6356 * 4.16
6357 */
6358 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6359 if (ctxt->error != NULL)
6360 ctxt->error(ctxt->userData,
6361 "Found anyName/except//anyName forbidden construct\n");
6362 ctxt->nbErrors++;
6363 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6364 if (ctxt->error != NULL)
6365 ctxt->error(ctxt->userData,
6366 "Found nsName/except//anyName forbidden construct\n");
6367 ctxt->nbErrors++;
6368 }
6369 }
6370 /*
6371 * Thisd is not an else since "include" is transformed
6372 * into a div
6373 */
6374 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6375 xmlChar *ns;
6376 xmlNodePtr child, ins, tmp;
6377
6378 /*
6379 * implements rule 4.11
6380 */
6381
6382 ns = xmlGetProp(cur, BAD_CAST "ns");
6383
6384 child = cur->children;
6385 ins = cur;
6386 while (child != NULL) {
6387 if (ns != NULL) {
6388 if (!xmlHasProp(child, BAD_CAST "ns")) {
6389 xmlSetProp(child, BAD_CAST "ns", ns);
6390 }
6391 }
6392 tmp = child->next;
6393 xmlUnlinkNode(child);
6394 ins = xmlAddNextSibling(ins, child);
6395 child = tmp;
6396 }
6397 if (ns != NULL)
6398 xmlFree(ns);
6399 delete = cur;
6400 goto skip_children;
6401 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006402 }
6403 }
6404 /*
6405 * Simplification 4.2 whitespaces
6406 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006407 else if ((cur->type == XML_TEXT_NODE) ||
6408 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006409 if (IS_BLANK_NODE(cur)) {
6410 if (cur->parent->type == XML_ELEMENT_NODE) {
6411 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6412 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6413 delete = cur;
6414 } else {
6415 delete = cur;
6416 goto skip_children;
6417 }
6418 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006419 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006420 delete = cur;
6421 goto skip_children;
6422 }
6423
6424 /*
6425 * Skip to next node
6426 */
6427 if (cur->children != NULL) {
6428 if ((cur->children->type != XML_ENTITY_DECL) &&
6429 (cur->children->type != XML_ENTITY_REF_NODE) &&
6430 (cur->children->type != XML_ENTITY_NODE)) {
6431 cur = cur->children;
6432 continue;
6433 }
6434 }
6435skip_children:
6436 if (cur->next != NULL) {
6437 cur = cur->next;
6438 continue;
6439 }
6440
6441 do {
6442 cur = cur->parent;
6443 if (cur == NULL)
6444 break;
6445 if (cur == root) {
6446 cur = NULL;
6447 break;
6448 }
6449 if (cur->next != NULL) {
6450 cur = cur->next;
6451 break;
6452 }
6453 } while (cur != NULL);
6454 }
6455 if (delete != NULL) {
6456 xmlUnlinkNode(delete);
6457 xmlFreeNode(delete);
6458 delete = NULL;
6459 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006460}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006461
Daniel Veillardc5312d72003-02-21 17:14:10 +00006462/**
6463 * xmlRelaxNGCleanupDoc:
6464 * @ctxt: a Relax-NG parser context
6465 * @doc: an xmldocPtr document pointer
6466 *
6467 * Cleanup the document from unwanted nodes for parsing, resolve
6468 * Include and externalRef lookups.
6469 *
6470 * Returns the cleaned up document or NULL in case of error
6471 */
6472static xmlDocPtr
6473xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6474 xmlNodePtr root;
6475
6476 /*
6477 * Extract the root
6478 */
6479 root = xmlDocGetRootElement(doc);
6480 if (root == NULL) {
6481 if (ctxt->error != NULL)
6482 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6483 ctxt->URL);
6484 ctxt->nbErrors++;
6485 return (NULL);
6486 }
6487 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006488 return(doc);
6489}
6490
6491/**
6492 * xmlRelaxNGParse:
6493 * @ctxt: a Relax-NG parser context
6494 *
6495 * parse a schema definition resource and build an internal
6496 * XML Shema struture which can be used to validate instances.
6497 * *WARNING* this interface is highly subject to change
6498 *
6499 * Returns the internal XML RelaxNG structure built from the resource or
6500 * NULL in case of error
6501 */
6502xmlRelaxNGPtr
6503xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6504{
6505 xmlRelaxNGPtr ret = NULL;
6506 xmlDocPtr doc;
6507 xmlNodePtr root;
6508
6509 xmlRelaxNGInitTypes();
6510
6511 if (ctxt == NULL)
6512 return (NULL);
6513
6514 /*
6515 * First step is to parse the input document into an DOM/Infoset
6516 */
6517 if (ctxt->URL != NULL) {
6518 doc = xmlParseFile((const char *) ctxt->URL);
6519 if (doc == NULL) {
6520 if (ctxt->error != NULL)
6521 ctxt->error(ctxt->userData,
6522 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6523 ctxt->nbErrors++;
6524 return (NULL);
6525 }
6526 } else if (ctxt->buffer != NULL) {
6527 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6528 if (doc == NULL) {
6529 if (ctxt->error != NULL)
6530 ctxt->error(ctxt->userData,
6531 "xmlRelaxNGParse: could not parse schemas\n");
6532 ctxt->nbErrors++;
6533 return (NULL);
6534 }
6535 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6536 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6537 } else {
6538 if (ctxt->error != NULL)
6539 ctxt->error(ctxt->userData,
6540 "xmlRelaxNGParse: nothing to parse\n");
6541 ctxt->nbErrors++;
6542 return (NULL);
6543 }
6544 ctxt->document = doc;
6545
6546 /*
6547 * Some preprocessing of the document content
6548 */
6549 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6550 if (doc == NULL) {
6551 xmlFreeDoc(ctxt->document);
6552 ctxt->document = NULL;
6553 return(NULL);
6554 }
6555
Daniel Veillard6eadf632003-01-23 18:29:16 +00006556 /*
6557 * Then do the parsing for good
6558 */
6559 root = xmlDocGetRootElement(doc);
6560 if (root == NULL) {
6561 if (ctxt->error != NULL)
6562 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6563 ctxt->URL);
6564 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006565 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006566 return (NULL);
6567 }
6568 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006569 if (ret == NULL) {
6570 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006571 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006572 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006573
6574 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006575 * Check the ref/defines links
6576 */
6577 /*
6578 * try to preprocess interleaves
6579 */
6580 if (ctxt->interleaves != NULL) {
6581 xmlHashScan(ctxt->interleaves,
6582 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6583 }
6584
6585 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006586 * if there was a parsing error return NULL
6587 */
6588 if (ctxt->nbErrors > 0) {
6589 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006590 ctxt->document = NULL;
6591 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006592 return(NULL);
6593 }
6594
6595 /*
6596 * Transfer the pointer for cleanup at the schema level.
6597 */
6598 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006599 ctxt->document = NULL;
6600 ret->documents = ctxt->documents;
6601 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006602
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006603 ret->includes = ctxt->includes;
6604 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006605 ret->defNr = ctxt->defNr;
6606 ret->defTab = ctxt->defTab;
6607 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006608 if (ctxt->idref == 1)
6609 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006610
6611 return (ret);
6612}
6613
6614/**
6615 * xmlRelaxNGSetParserErrors:
6616 * @ctxt: a Relax-NG validation context
6617 * @err: the error callback
6618 * @warn: the warning callback
6619 * @ctx: contextual data for the callbacks
6620 *
6621 * Set the callback functions used to handle errors for a validation context
6622 */
6623void
6624xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6625 xmlRelaxNGValidityErrorFunc err,
6626 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6627 if (ctxt == NULL)
6628 return;
6629 ctxt->error = err;
6630 ctxt->warning = warn;
6631 ctxt->userData = ctx;
6632}
6633/************************************************************************
6634 * *
6635 * Dump back a compiled form *
6636 * *
6637 ************************************************************************/
6638static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6639
6640/**
6641 * xmlRelaxNGDumpDefines:
6642 * @output: the file output
6643 * @defines: a list of define structures
6644 *
6645 * Dump a RelaxNG structure back
6646 */
6647static void
6648xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6649 while (defines != NULL) {
6650 xmlRelaxNGDumpDefine(output, defines);
6651 defines = defines->next;
6652 }
6653}
6654
6655/**
6656 * xmlRelaxNGDumpDefine:
6657 * @output: the file output
6658 * @define: a define structure
6659 *
6660 * Dump a RelaxNG structure back
6661 */
6662static void
6663xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6664 if (define == NULL)
6665 return;
6666 switch(define->type) {
6667 case XML_RELAXNG_EMPTY:
6668 fprintf(output, "<empty/>\n");
6669 break;
6670 case XML_RELAXNG_NOT_ALLOWED:
6671 fprintf(output, "<notAllowed/>\n");
6672 break;
6673 case XML_RELAXNG_TEXT:
6674 fprintf(output, "<text/>\n");
6675 break;
6676 case XML_RELAXNG_ELEMENT:
6677 fprintf(output, "<element>\n");
6678 if (define->name != NULL) {
6679 fprintf(output, "<name");
6680 if (define->ns != NULL)
6681 fprintf(output, " ns=\"%s\"", define->ns);
6682 fprintf(output, ">%s</name>\n", define->name);
6683 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006684 xmlRelaxNGDumpDefines(output, define->attrs);
6685 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006686 fprintf(output, "</element>\n");
6687 break;
6688 case XML_RELAXNG_LIST:
6689 fprintf(output, "<list>\n");
6690 xmlRelaxNGDumpDefines(output, define->content);
6691 fprintf(output, "</list>\n");
6692 break;
6693 case XML_RELAXNG_ONEORMORE:
6694 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006695 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006696 fprintf(output, "</oneOrMore>\n");
6697 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006698 case XML_RELAXNG_ZEROORMORE:
6699 fprintf(output, "<zeroOrMore>\n");
6700 xmlRelaxNGDumpDefines(output, define->content);
6701 fprintf(output, "</zeroOrMore>\n");
6702 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006703 case XML_RELAXNG_CHOICE:
6704 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006705 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006706 fprintf(output, "</choice>\n");
6707 break;
6708 case XML_RELAXNG_GROUP:
6709 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006710 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006711 fprintf(output, "</group>\n");
6712 break;
6713 case XML_RELAXNG_INTERLEAVE:
6714 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006715 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006716 fprintf(output, "</interleave>\n");
6717 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006718 case XML_RELAXNG_OPTIONAL:
6719 fprintf(output, "<optional>\n");
6720 xmlRelaxNGDumpDefines(output, define->content);
6721 fprintf(output, "</optional>\n");
6722 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006723 case XML_RELAXNG_ATTRIBUTE:
6724 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006725 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006726 fprintf(output, "</attribute>\n");
6727 break;
6728 case XML_RELAXNG_DEF:
6729 fprintf(output, "<define");
6730 if (define->name != NULL)
6731 fprintf(output, " name=\"%s\"", define->name);
6732 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006733 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006734 fprintf(output, "</define>\n");
6735 break;
6736 case XML_RELAXNG_REF:
6737 fprintf(output, "<ref");
6738 if (define->name != NULL)
6739 fprintf(output, " name=\"%s\"", define->name);
6740 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006741 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006742 fprintf(output, "</ref>\n");
6743 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006744 case XML_RELAXNG_PARENTREF:
6745 fprintf(output, "<parentRef");
6746 if (define->name != NULL)
6747 fprintf(output, " name=\"%s\"", define->name);
6748 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006749 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006750 fprintf(output, "</parentRef>\n");
6751 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006752 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006753 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006754 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006755 fprintf(output, "</externalRef>\n");
6756 break;
6757 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006758 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006759 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006760 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006761 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006762 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006763 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006764 TODO
6765 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006766 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006767 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006768 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006769 }
6770}
6771
6772/**
6773 * xmlRelaxNGDumpGrammar:
6774 * @output: the file output
6775 * @grammar: a grammar structure
6776 * @top: is this a top grammar
6777 *
6778 * Dump a RelaxNG structure back
6779 */
6780static void
6781xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6782{
6783 if (grammar == NULL)
6784 return;
6785
6786 fprintf(output, "<grammar");
6787 if (top)
6788 fprintf(output,
6789 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6790 switch(grammar->combine) {
6791 case XML_RELAXNG_COMBINE_UNDEFINED:
6792 break;
6793 case XML_RELAXNG_COMBINE_CHOICE:
6794 fprintf(output, " combine=\"choice\"");
6795 break;
6796 case XML_RELAXNG_COMBINE_INTERLEAVE:
6797 fprintf(output, " combine=\"interleave\"");
6798 break;
6799 default:
6800 fprintf(output, " <!-- invalid combine value -->");
6801 }
6802 fprintf(output, ">\n");
6803 if (grammar->start == NULL) {
6804 fprintf(output, " <!-- grammar had no start -->");
6805 } else {
6806 fprintf(output, "<start>\n");
6807 xmlRelaxNGDumpDefine(output, grammar->start);
6808 fprintf(output, "</start>\n");
6809 }
6810 /* TODO ? Dump the defines ? */
6811 fprintf(output, "</grammar>\n");
6812}
6813
6814/**
6815 * xmlRelaxNGDump:
6816 * @output: the file output
6817 * @schema: a schema structure
6818 *
6819 * Dump a RelaxNG structure back
6820 */
6821void
6822xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6823{
6824 if (schema == NULL) {
6825 fprintf(output, "RelaxNG empty or failed to compile\n");
6826 return;
6827 }
6828 fprintf(output, "RelaxNG: ");
6829 if (schema->doc == NULL) {
6830 fprintf(output, "no document\n");
6831 } else if (schema->doc->URL != NULL) {
6832 fprintf(output, "%s\n", schema->doc->URL);
6833 } else {
6834 fprintf(output, "\n");
6835 }
6836 if (schema->topgrammar == NULL) {
6837 fprintf(output, "RelaxNG has no top grammar\n");
6838 return;
6839 }
6840 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6841}
6842
Daniel Veillardfebcca42003-02-16 15:44:18 +00006843/**
6844 * xmlRelaxNGDumpTree:
6845 * @output: the file output
6846 * @schema: a schema structure
6847 *
6848 * Dump the transformed RelaxNG tree.
6849 */
6850void
6851xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6852{
6853 if (schema == NULL) {
6854 fprintf(output, "RelaxNG empty or failed to compile\n");
6855 return;
6856 }
6857 if (schema->doc == NULL) {
6858 fprintf(output, "no document\n");
6859 } else {
6860 xmlDocDump(output, schema->doc);
6861 }
6862}
6863
Daniel Veillard6eadf632003-01-23 18:29:16 +00006864/************************************************************************
6865 * *
6866 * Validation implementation *
6867 * *
6868 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006869static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6870 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006871static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6872 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006873
6874/**
6875 * xmlRelaxNGSkipIgnored:
6876 * @ctxt: a schema validation context
6877 * @node: the top node.
6878 *
6879 * Skip ignorable nodes in that context
6880 *
6881 * Returns the new sibling or NULL in case of error.
6882 */
6883static xmlNodePtr
6884xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6885 xmlNodePtr node) {
6886 /*
6887 * TODO complete and handle entities
6888 */
6889 while ((node != NULL) &&
6890 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006891 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006892 (((node->type == XML_TEXT_NODE) ||
6893 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00006894 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
6895 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006896 node = node->next;
6897 }
6898 return(node);
6899}
6900
6901/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006902 * xmlRelaxNGNormalize:
6903 * @ctxt: a schema validation context
6904 * @str: the string to normalize
6905 *
6906 * Implements the normalizeWhiteSpace( s ) function from
6907 * section 6.2.9 of the spec
6908 *
6909 * Returns the new string or NULL in case of error.
6910 */
6911static xmlChar *
6912xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6913 xmlChar *ret, *p;
6914 const xmlChar *tmp;
6915 int len;
6916
6917 if (str == NULL)
6918 return(NULL);
6919 tmp = str;
6920 while (*tmp != 0) tmp++;
6921 len = tmp - str;
6922
6923 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6924 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006925 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006926 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006927 } else {
6928 xmlGenericError(xmlGenericErrorContext,
6929 "xmlRelaxNGNormalize: out of memory\n");
6930 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006931 return(NULL);
6932 }
6933 p = ret;
6934 while (IS_BLANK(*str)) str++;
6935 while (*str != 0) {
6936 if (IS_BLANK(*str)) {
6937 while (IS_BLANK(*str)) str++;
6938 if (*str == 0)
6939 break;
6940 *p++ = ' ';
6941 } else
6942 *p++ = *str++;
6943 }
6944 *p = 0;
6945 return(ret);
6946}
6947
6948/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006949 * xmlRelaxNGValidateDatatype:
6950 * @ctxt: a Relax-NG validation context
6951 * @value: the string value
6952 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006953 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006954 *
6955 * Validate the given value against the dataype
6956 *
6957 * Returns 0 if the validation succeeded or an error code.
6958 */
6959static int
6960xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006961 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006962 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006963 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006964 void *result = NULL;
6965 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006966
6967 if ((define == NULL) || (define->data == NULL)) {
6968 return(-1);
6969 }
6970 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006971 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006972 if ((define->attrs != NULL) &&
6973 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006974 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006975 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006976 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006977 }
6978 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006979 ret = -1;
6980 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006981 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006982 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6983 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006984 return(-1);
6985 } else if (ret == 1) {
6986 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006987 } else if (ret == 2) {
6988 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006989 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006990 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006991 ret = -1;
6992 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006993 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006994 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
6995 if (lib->facet != NULL) {
6996 tmp = lib->facet(lib->data, define->name, cur->name,
6997 cur->value, value, result);
6998 if (tmp != 0)
6999 ret = -1;
7000 }
7001 cur = cur->next;
7002 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007003 if ((ret == 0) && (define->content != NULL)) {
7004 const xmlChar *oldvalue, *oldendvalue;
7005
7006 oldvalue = ctxt->state->value;
7007 oldendvalue = ctxt->state->endvalue;
7008 ctxt->state->value = (xmlChar *) value;
7009 ctxt->state->endvalue = NULL;
7010 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7011 ctxt->state->value = (xmlChar *) oldvalue;
7012 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7013 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007014 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7015 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007016 return(ret);
7017}
7018
7019/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007020 * xmlRelaxNGNextValue:
7021 * @ctxt: a Relax-NG validation context
7022 *
7023 * Skip to the next value when validating within a list
7024 *
7025 * Returns 0 if the operation succeeded or an error code.
7026 */
7027static int
7028xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7029 xmlChar *cur;
7030
7031 cur = ctxt->state->value;
7032 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7033 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007034 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007035 return(0);
7036 }
7037 while (*cur != 0) cur++;
7038 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7039 if (cur == ctxt->state->endvalue)
7040 ctxt->state->value = NULL;
7041 else
7042 ctxt->state->value = cur;
7043 return(0);
7044}
7045
7046/**
7047 * xmlRelaxNGValidateValueList:
7048 * @ctxt: a Relax-NG validation context
7049 * @defines: the list of definitions to verify
7050 *
7051 * Validate the given set of definitions for the current value
7052 *
7053 * Returns 0 if the validation succeeded or an error code.
7054 */
7055static int
7056xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7057 xmlRelaxNGDefinePtr defines) {
7058 int ret = 0;
7059
7060 while (defines != NULL) {
7061 ret = xmlRelaxNGValidateValue(ctxt, defines);
7062 if (ret != 0)
7063 break;
7064 defines = defines->next;
7065 }
7066 return(ret);
7067}
7068
7069/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007070 * xmlRelaxNGValidateValue:
7071 * @ctxt: a Relax-NG validation context
7072 * @define: the definition to verify
7073 *
7074 * Validate the given definition for the current value
7075 *
7076 * Returns 0 if the validation succeeded or an error code.
7077 */
7078static int
7079xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7080 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007081 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007082 xmlChar *value;
7083
7084 value = ctxt->state->value;
7085 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007086 case XML_RELAXNG_EMPTY: {
7087 if ((value != NULL) && (value[0] != 0)) {
7088 int idx = 0;
7089
7090 while (IS_BLANK(value[idx]))
7091 idx++;
7092 if (value[idx] != 0)
7093 ret = -1;
7094 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007095 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007096 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007097 case XML_RELAXNG_TEXT:
7098 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007099 case XML_RELAXNG_VALUE: {
7100 if (!xmlStrEqual(value, define->value)) {
7101 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007102 xmlRelaxNGTypeLibraryPtr lib;
7103
7104 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
7105 if ((lib != NULL) && (lib->comp != NULL))
7106 ret = lib->comp(lib->data, define->name, value,
7107 define->value);
7108 else
7109 ret = -1;
7110 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007111 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007112 return(-1);
7113 } else if (ret == 1) {
7114 ret = 0;
7115 } else {
7116 ret = -1;
7117 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007118 } else {
7119 xmlChar *nval, *nvalue;
7120
7121 /*
7122 * TODO: trivial optimizations are possible by
7123 * computing at compile-time
7124 */
7125 nval = xmlRelaxNGNormalize(ctxt, define->value);
7126 nvalue = xmlRelaxNGNormalize(ctxt, value);
7127
Daniel Veillardea3f3982003-01-26 19:45:18 +00007128 if ((nval == NULL) || (nvalue == NULL) ||
7129 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007130 ret = -1;
7131 if (nval != NULL)
7132 xmlFree(nval);
7133 if (nvalue != NULL)
7134 xmlFree(nvalue);
7135 }
7136 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007137 if (ret == 0)
7138 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007139 break;
7140 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007141 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007142 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7143 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007144 if (ret == 0)
7145 xmlRelaxNGNextValue(ctxt);
7146
7147 break;
7148 }
7149 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007150 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007151 xmlChar *oldvalue;
7152
7153 oldflags = ctxt->flags;
7154 ctxt->flags |= FLAGS_IGNORABLE;
7155
7156 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007157 while (list != NULL) {
7158 ret = xmlRelaxNGValidateValue(ctxt, list);
7159 if (ret == 0) {
7160 break;
7161 }
7162 ctxt->state->value = oldvalue;
7163 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007164 }
7165 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007166 if (ret != 0) {
7167 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7168 xmlRelaxNGDumpValidError(ctxt);
7169 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007170 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007171 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007172 if (ret == 0)
7173 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007174 break;
7175 }
7176 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007177 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007178 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007179#ifdef DEBUG_LIST
7180 int nb_values = 0;
7181#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007182
7183 oldvalue = ctxt->state->value;
7184 oldend = ctxt->state->endvalue;
7185
7186 val = xmlStrdup(oldvalue);
7187 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007188 val = xmlStrdup(BAD_CAST "");
7189 }
7190 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007191 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007192 return(-1);
7193 }
7194 cur = val;
7195 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007196 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007197 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007198 cur++;
7199#ifdef DEBUG_LIST
7200 nb_values++;
7201#endif
7202 while (IS_BLANK(*cur))
7203 *cur++ = 0;
7204 } else
7205 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007206 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007207#ifdef DEBUG_LIST
7208 xmlGenericError(xmlGenericErrorContext,
7209 "list value: '%s' found %d items\n", oldvalue, nb_values);
7210 nb_values = 0;
7211#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007212 ctxt->state->endvalue = cur;
7213 cur = val;
7214 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007215
Daniel Veillardfd573f12003-03-16 17:52:32 +00007216 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007217
Daniel Veillardfd573f12003-03-16 17:52:32 +00007218 while (list != NULL) {
7219 if (ctxt->state->value == ctxt->state->endvalue)
7220 ctxt->state->value = NULL;
7221 ret = xmlRelaxNGValidateValue(ctxt, list);
7222 if (ret != 0) {
7223#ifdef DEBUG_LIST
7224 xmlGenericError(xmlGenericErrorContext,
7225 "Failed to validate value: '%s' with %d rule\n",
7226 ctxt->state->value, nb_values);
7227#endif
7228 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007229 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007230#ifdef DEBUG_LIST
7231 nb_values++;
7232#endif
7233 list = list->next;
7234 }
7235
7236 if ((ret == 0) && (ctxt->state->value != NULL) &&
7237 (ctxt->state->value != ctxt->state->endvalue)) {
7238 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7239 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007240 }
7241 xmlFree(val);
7242 ctxt->state->value = oldvalue;
7243 ctxt->state->endvalue = oldend;
7244 break;
7245 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007246 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007247 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7248 if (ret != 0) {
7249 break;
7250 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007251 /* no break on purpose */
7252 case XML_RELAXNG_ZEROORMORE: {
7253 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007254
7255 oldflags = ctxt->flags;
7256 ctxt->flags |= FLAGS_IGNORABLE;
7257 cur = ctxt->state->value;
7258 temp = NULL;
7259 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7260 (temp != cur)) {
7261 temp = cur;
7262 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7263 if (ret != 0) {
7264 ctxt->state->value = temp;
7265 ret = 0;
7266 break;
7267 }
7268 cur = ctxt->state->value;
7269 }
7270 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007271 if (ret != 0) {
7272 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7273 xmlRelaxNGDumpValidError(ctxt);
7274 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007275 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007276 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007277 break;
7278 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007279 case XML_RELAXNG_EXCEPT: {
7280 xmlRelaxNGDefinePtr list;
7281
7282 list = define->content;
7283 while (list != NULL) {
7284 ret = xmlRelaxNGValidateValue(ctxt, list);
7285 if (ret == 0) {
7286 ret = -1;
7287 break;
7288 } else
7289 ret = 0;
7290 list = list->next;
7291 }
7292 break;
7293 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007294 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007295 case XML_RELAXNG_GROUP: {
7296 xmlRelaxNGDefinePtr list;
7297
7298 list = define->content;
7299 while (list != NULL) {
7300 ret = xmlRelaxNGValidateValue(ctxt, list);
7301 if (ret != 0) {
7302 ret = -1;
7303 break;
7304 } else
7305 ret = 0;
7306 list = list->next;
7307 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007308 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007309 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007310 case XML_RELAXNG_REF:
7311 case XML_RELAXNG_PARENTREF:
7312 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7313 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007314 default:
7315 TODO
7316 ret = -1;
7317 }
7318 return(ret);
7319}
7320
7321/**
7322 * xmlRelaxNGValidateValueContent:
7323 * @ctxt: a Relax-NG validation context
7324 * @defines: the list of definitions to verify
7325 *
7326 * Validate the given definitions for the current value
7327 *
7328 * Returns 0 if the validation succeeded or an error code.
7329 */
7330static int
7331xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7332 xmlRelaxNGDefinePtr defines) {
7333 int ret = 0;
7334
7335 while (defines != NULL) {
7336 ret = xmlRelaxNGValidateValue(ctxt, defines);
7337 if (ret != 0)
7338 break;
7339 defines = defines->next;
7340 }
7341 return(ret);
7342}
7343
7344/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007345 * xmlRelaxNGAttributeMatch:
7346 * @ctxt: a Relax-NG validation context
7347 * @define: the definition to check
7348 * @prop: the attribute
7349 *
7350 * Check if the attribute matches the definition nameClass
7351 *
7352 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7353 */
7354static int
7355xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7356 xmlRelaxNGDefinePtr define,
7357 xmlAttrPtr prop) {
7358 int ret;
7359
7360 if (define->name != NULL) {
7361 if (!xmlStrEqual(define->name, prop->name))
7362 return(0);
7363 }
7364 if (define->ns != NULL) {
7365 if (define->ns[0] == 0) {
7366 if (prop->ns != NULL)
7367 return(0);
7368 } else {
7369 if ((prop->ns == NULL) ||
7370 (!xmlStrEqual(define->ns, prop->ns->href)))
7371 return(0);
7372 }
7373 }
7374 if (define->nameClass == NULL)
7375 return(1);
7376 define = define->nameClass;
7377 if (define->type == XML_RELAXNG_EXCEPT) {
7378 xmlRelaxNGDefinePtr list;
7379
7380 list = define->content;
7381 while (list != NULL) {
7382 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7383 if (ret == 1)
7384 return(0);
7385 if (ret < 0)
7386 return(ret);
7387 list = list->next;
7388 }
7389 } else {
7390 TODO
7391 }
7392 return(1);
7393}
7394
7395/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007396 * xmlRelaxNGValidateAttribute:
7397 * @ctxt: a Relax-NG validation context
7398 * @define: the definition to verify
7399 *
7400 * Validate the given attribute definition for that node
7401 *
7402 * Returns 0 if the validation succeeded or an error code.
7403 */
7404static int
7405xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7406 xmlRelaxNGDefinePtr define) {
7407 int ret = 0, i;
7408 xmlChar *value, *oldvalue;
7409 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007410 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007411
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007412 if (ctxt->state->nbAttrLeft <= 0)
7413 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007414 if (define->name != NULL) {
7415 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7416 tmp = ctxt->state->attrs[i];
7417 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7418 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7419 (tmp->ns == NULL)) ||
7420 ((tmp->ns != NULL) &&
7421 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7422 prop = tmp;
7423 break;
7424 }
7425 }
7426 }
7427 if (prop != NULL) {
7428 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7429 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007430 oldseq = ctxt->state->seq;
7431 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007432 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007433 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007434 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007435 if (ctxt->state->value != NULL)
7436 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007437 if (value != NULL)
7438 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007439 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007440 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007441 if (ret == 0) {
7442 /*
7443 * flag the attribute as processed
7444 */
7445 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007446 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007447 }
7448 } else {
7449 ret = -1;
7450 }
7451#ifdef DEBUG
7452 xmlGenericError(xmlGenericErrorContext,
7453 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7454#endif
7455 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007456 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7457 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007458 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007459 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007460 prop = tmp;
7461 break;
7462 }
7463 }
7464 if (prop != NULL) {
7465 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7466 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007467 oldseq = ctxt->state->seq;
7468 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007469 ctxt->state->value = value;
7470 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007471 if (ctxt->state->value != NULL)
7472 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007473 if (value != NULL)
7474 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007475 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007476 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007477 if (ret == 0) {
7478 /*
7479 * flag the attribute as processed
7480 */
7481 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007482 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007483 }
7484 } else {
7485 ret = -1;
7486 }
7487#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007488 if (define->ns != NULL) {
7489 xmlGenericError(xmlGenericErrorContext,
7490 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7491 define->ns, ret);
7492 } else {
7493 xmlGenericError(xmlGenericErrorContext,
7494 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7495 ret);
7496 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007497#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007498 }
7499
7500 return(ret);
7501}
7502
7503/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007504 * xmlRelaxNGValidateAttributeList:
7505 * @ctxt: a Relax-NG validation context
7506 * @define: the list of definition to verify
7507 *
7508 * Validate the given node against the list of attribute definitions
7509 *
7510 * Returns 0 if the validation succeeded or an error code.
7511 */
7512static int
7513xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7514 xmlRelaxNGDefinePtr defines) {
7515 int ret = 0;
7516 while (defines != NULL) {
7517 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7518 ret = -1;
7519 defines = defines->next;
7520 }
7521 return(ret);
7522}
7523
7524/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007525 * xmlRelaxNGNodeMatchesList:
7526 * @node: the node
7527 * @list: a NULL terminated array of definitions
7528 *
7529 * Check if a node can be matched by one of the definitions
7530 *
7531 * Returns 1 if matches 0 otherwise
7532 */
7533static int
7534xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7535 xmlRelaxNGDefinePtr cur;
7536 int i = 0;
7537
7538 if ((node == NULL) || (list == NULL))
7539 return(0);
7540
7541 cur = list[i++];
7542 while (cur != NULL) {
7543 if ((node->type == XML_ELEMENT_NODE) &&
7544 (cur->type == XML_RELAXNG_ELEMENT)) {
7545 if (cur->name == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007546 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7547 if (node->ns == NULL)
7548 return(1);
7549 } else {
7550 if ((node->ns != NULL) &&
7551 (xmlStrEqual(node->ns->href, cur->ns)))
7552 return(1);
7553 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007554 } else if (xmlStrEqual(cur->name, node->name)) {
7555 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7556 if (node->ns == NULL)
7557 return(1);
7558 } else {
7559 if ((node->ns != NULL) &&
7560 (xmlStrEqual(node->ns->href, cur->ns)))
7561 return(1);
7562 }
7563 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007564 } else if (((node->type == XML_TEXT_NODE) ||
7565 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007566 (cur->type == XML_RELAXNG_TEXT)) {
7567 return(1);
7568 }
7569 cur = list[i++];
7570 }
7571 return(0);
7572}
7573
7574/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007575 * xmlRelaxNGValidateInterleave:
7576 * @ctxt: a Relax-NG validation context
7577 * @define: the definition to verify
7578 *
7579 * Validate an interleave definition for a node.
7580 *
7581 * Returns 0 if the validation succeeded or an error code.
7582 */
7583static int
7584xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7585 xmlRelaxNGDefinePtr define) {
7586 int ret = 0, i, nbgroups, left;
7587 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007588 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007589
7590 xmlRelaxNGValidStatePtr oldstate;
7591 xmlRelaxNGPartitionPtr partitions;
7592 xmlRelaxNGInterleaveGroupPtr group = NULL;
7593 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7594 xmlNodePtr *list = NULL, *lasts = NULL;
7595
7596 if (define->data != NULL) {
7597 partitions = (xmlRelaxNGPartitionPtr) define->data;
7598 nbgroups = partitions->nbgroups;
7599 left = nbgroups;
7600 } else {
7601 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7602 return(-1);
7603 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007604 /*
7605 * Optimizations for MIXED
7606 */
7607 oldflags = ctxt->flags;
7608 if (define->flags & IS_MIXED) {
7609 ctxt->flags |= FLAGS_MIXED_CONTENT;
7610 if (nbgroups == 2) {
7611 /*
7612 * this is a pure <mixed> case
7613 */
7614 if (ctxt->state != NULL)
7615 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7616 ctxt->state->seq);
7617 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7618 ret = xmlRelaxNGValidateDefinition(ctxt,
7619 partitions->groups[1]->rule);
7620 else
7621 ret = xmlRelaxNGValidateDefinition(ctxt,
7622 partitions->groups[0]->rule);
7623 if (ret == 0) {
7624 if (ctxt->state != NULL)
7625 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7626 ctxt->state->seq);
7627 }
7628 ctxt->flags = oldflags;
7629 return(ret);
7630 }
7631 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007632
7633 /*
7634 * Build arrays to store the first and last node of the chain
7635 * pertaining to each group
7636 */
7637 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7638 if (list == NULL) {
7639 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7640 return(-1);
7641 }
7642 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7643 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7644 if (lasts == NULL) {
7645 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7646 return(-1);
7647 }
7648 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7649
7650 /*
7651 * Walk the sequence of children finding the right group and
7652 * sorting them in sequences.
7653 */
7654 cur = ctxt->state->seq;
7655 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7656 start = cur;
7657 while (cur != NULL) {
7658 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007659 if ((partitions->triage != NULL) &&
7660 (partitions->flags & IS_DETERMINIST)) {
7661 void *tmp = NULL;
7662
7663 if ((cur->type == XML_TEXT_NODE) ||
7664 (cur->type == XML_CDATA_SECTION_NODE)) {
7665 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7666 NULL);
7667 } else if (cur->type == XML_ELEMENT_NODE) {
7668 if (cur->ns != NULL) {
7669 tmp = xmlHashLookup2(partitions->triage, cur->name,
7670 cur->ns->href);
7671 if (tmp == NULL)
7672 tmp = xmlHashLookup2(partitions->triage,
7673 BAD_CAST "#any", cur->ns->href);
7674 } else
7675 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7676 if (tmp == NULL)
7677 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7678 NULL);
7679 }
7680
7681 if (tmp == NULL) {
7682 i = nbgroups;
7683 } else {
7684 i = ((long) tmp) - 1;
7685 if (partitions->flags & IS_NEEDCHECK) {
7686 group = partitions->groups[i];
7687 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7688 i = nbgroups;
7689 }
7690 }
7691 } else {
7692 for (i = 0;i < nbgroups;i++) {
7693 group = partitions->groups[i];
7694 if (group == NULL)
7695 continue;
7696 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7697 break;
7698 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007699 }
7700 /*
7701 * We break as soon as an element not matched is found
7702 */
7703 if (i >= nbgroups) {
7704 break;
7705 }
7706 if (lasts[i] != NULL) {
7707 lasts[i]->next = cur;
7708 lasts[i] = cur;
7709 } else {
7710 list[i] = cur;
7711 lasts[i] = cur;
7712 }
7713 if (cur->next != NULL)
7714 lastchg = cur->next;
7715 else
7716 lastchg = cur;
7717 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7718 }
7719 if (ret != 0) {
7720 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7721 ret = -1;
7722 goto done;
7723 }
7724 lastelem = cur;
7725 oldstate = ctxt->state;
7726 for (i = 0;i < nbgroups;i++) {
7727 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7728 group = partitions->groups[i];
7729 if (lasts[i] != NULL) {
7730 last = lasts[i]->next;
7731 lasts[i]->next = NULL;
7732 }
7733 ctxt->state->seq = list[i];
7734 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7735 if (ret != 0)
7736 break;
7737 if (ctxt->state != NULL) {
7738 cur = ctxt->state->seq;
7739 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007740 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007741 oldstate = ctxt->state;
7742 ctxt->state = NULL;
7743 if (cur != NULL) {
7744 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7745 ret = -1;
7746 ctxt->state = oldstate;
7747 goto done;
7748 }
7749 } else if (ctxt->states != NULL) {
7750 int j;
7751 int found = 0;
7752
7753 for (j = 0;j < ctxt->states->nbState;j++) {
7754 cur = ctxt->states->tabState[j]->seq;
7755 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7756 if (cur == NULL) {
7757 found = 1;
7758 break;
7759 }
7760 }
7761 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007762 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007763 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7764 }
7765 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007766 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007767 }
7768 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7769 ctxt->states = NULL;
7770 if (found == 0) {
7771 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7772 ret = -1;
7773 ctxt->state = oldstate;
7774 goto done;
7775 }
7776 } else {
7777 ret = -1;
7778 break;
7779 }
7780 if (lasts[i] != NULL) {
7781 lasts[i]->next = last;
7782 }
7783 }
7784 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007785 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007786 ctxt->state = oldstate;
7787 ctxt->state->seq = lastelem;
7788 if (ret != 0) {
7789 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7790 ret = -1;
7791 goto done;
7792 }
7793
7794done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007795 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007796 /*
7797 * builds the next links chain from the prev one
7798 */
7799 cur = lastchg;
7800 while (cur != NULL) {
7801 if ((cur == start) || (cur->prev == NULL))
7802 break;
7803 cur->prev->next = cur;
7804 cur = cur->prev;
7805 }
7806 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007807 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007808 }
7809
7810 xmlFree(list);
7811 xmlFree(lasts);
7812 return(ret);
7813}
7814
7815/**
7816 * xmlRelaxNGValidateDefinitionList:
7817 * @ctxt: a Relax-NG validation context
7818 * @define: the list of definition to verify
7819 *
7820 * Validate the given node content against the (list) of definitions
7821 *
7822 * Returns 0 if the validation succeeded or an error code.
7823 */
7824static int
7825xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7826 xmlRelaxNGDefinePtr defines) {
7827 int ret = 0, res;
7828
7829
Daniel Veillard952379b2003-03-17 15:37:12 +00007830 if (defines == NULL) {
7831 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7832 return(-1);
7833 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007834 while (defines != NULL) {
7835 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7836 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7837 if (res < 0)
7838 ret = -1;
7839 } else {
7840 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7841 return(-1);
7842 }
7843 if (ret < 0)
7844 break;
7845 defines = defines->next;
7846 }
7847
7848 return(ret);
7849}
7850
7851/**
7852 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007853 * @ctxt: a Relax-NG validation context
7854 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007855 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007856 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007857 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007858 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007859 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007860 */
7861static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007862xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7863 xmlRelaxNGDefinePtr define,
7864 xmlNodePtr elem) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007865 int ret = 0, oldflags;
Daniel Veillard416589a2003-02-17 17:25:42 +00007866
Daniel Veillardfd573f12003-03-16 17:52:32 +00007867 if (define->name != NULL) {
7868 if (!xmlStrEqual(elem->name, define->name)) {
7869 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7870 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007871 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007872 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007873 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7874 if (elem->ns == NULL) {
7875 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7876 elem->name);
7877 return(0);
7878 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7879 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7880 elem->name, define->ns);
7881 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007882 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007883 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7884 (define->name == NULL)) {
7885 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7886 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007887 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007888 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7889 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7890 define->name);
7891 return(0);
7892 }
7893
7894 if (define->nameClass == NULL)
7895 return(1);
7896
7897 define = define->nameClass;
7898 if (define->type == XML_RELAXNG_EXCEPT) {
7899 xmlRelaxNGDefinePtr list;
7900 oldflags = ctxt->flags;
7901 ctxt->flags |= FLAGS_IGNORABLE;
7902
7903 list = define->content;
7904 while (list != NULL) {
7905 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7906 if (ret == 1) {
7907 ctxt->flags = oldflags;
7908 return(0);
7909 }
7910 if (ret < 0) {
7911 ctxt->flags = oldflags;
7912 return(ret);
7913 }
7914 list = list->next;
7915 }
7916 ret = 1;
7917 ctxt->flags = oldflags;
7918 } else if (define->type == XML_RELAXNG_CHOICE) {
7919 xmlRelaxNGDefinePtr list;
7920
7921 oldflags = ctxt->flags;
7922 ctxt->flags |= FLAGS_IGNORABLE;
7923
7924 list = define->nameClass;
7925 while (list != NULL) {
7926 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7927 if (ret == 1) {
7928 ctxt->flags = oldflags;
7929 return(1);
7930 }
7931 if (ret < 0) {
7932 ctxt->flags = oldflags;
7933 return(ret);
7934 }
7935 list = list->next;
7936 }
7937 if (ret != 0) {
7938 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7939 xmlRelaxNGDumpValidError(ctxt);
7940 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007941 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007942 }
7943 ret = 0;
7944 ctxt->flags = oldflags;
7945 } else {
7946 TODO
7947 ret = -1;
7948 }
7949 return(ret);
7950}
7951
7952/**
7953 * xmlRelaxNGValidateElementEnd:
7954 * @ctxt: a Relax-NG validation context
7955 *
7956 * Validate the end of the element, implements check that
7957 * there is nothing left not consumed in the element content
7958 * or in the attribute list.
7959 *
7960 * Returns 0 if the validation succeeded or an error code.
7961 */
7962static int
7963xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
7964 int ret = 0, i;
7965 xmlRelaxNGValidStatePtr state;
7966
7967 state = ctxt->state;
7968 if (state->seq != NULL) {
7969 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
7970 if (state->seq != NULL) {
7971 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
7972 state->node->name, state->seq->name);
7973 ret = -1;
7974 }
7975 }
7976 for (i = 0;i < state->nbAttrs;i++) {
7977 if (state->attrs[i] != NULL) {
7978 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
7979 state->attrs[i]->name, state->node->name);
7980 ret = -1;
7981 }
7982 }
7983 return(ret);
7984}
7985
7986/**
7987 * xmlRelaxNGValidateState:
7988 * @ctxt: a Relax-NG validation context
7989 * @define: the definition to verify
7990 *
7991 * Validate the current state against the definition
7992 *
7993 * Returns 0 if the validation succeeded or an error code.
7994 */
7995static int
7996xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
7997 xmlRelaxNGDefinePtr define) {
7998 xmlNodePtr node;
7999 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008000 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008001
8002 if (define == NULL) {
8003 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8004 return(-1);
8005 }
8006
8007 if (ctxt->state != NULL) {
8008 node = ctxt->state->seq;
8009 } else {
8010 node = NULL;
8011 }
8012#ifdef DEBUG
8013 for (i = 0;i < ctxt->depth;i++)
8014 xmlGenericError(xmlGenericErrorContext, " ");
8015 xmlGenericError(xmlGenericErrorContext,
8016 "Start validating %s ", xmlRelaxNGDefName(define));
8017 if (define->name != NULL)
8018 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8019 if ((node != NULL) && (node->name != NULL))
8020 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8021 else
8022 xmlGenericError(xmlGenericErrorContext, "\n");
8023#endif
8024 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008025 switch (define->type) {
8026 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008027 node = xmlRelaxNGSkipIgnored(ctxt, node);
8028 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008029 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008030 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008031 ret = -1;
8032 break;
8033 case XML_RELAXNG_TEXT:
8034 while ((node != NULL) &&
8035 ((node->type == XML_TEXT_NODE) ||
8036 (node->type == XML_COMMENT_NODE) ||
8037 (node->type == XML_PI_NODE) ||
8038 (node->type == XML_CDATA_SECTION_NODE)))
8039 node = node->next;
8040 ctxt->state->seq = node;
8041 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008042 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008043 errNr = ctxt->errNr;
8044 node = xmlRelaxNGSkipIgnored(ctxt, node);
8045 if (node == NULL) {
8046 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8047 ret = -1;
8048 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8049 xmlRelaxNGDumpValidError(ctxt);
8050 break;
8051 }
8052 if (node->type != XML_ELEMENT_NODE) {
8053 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8054 ret = -1;
8055 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8056 xmlRelaxNGDumpValidError(ctxt);
8057 break;
8058 }
8059 /*
8060 * This node was already validated successfully against
8061 * this definition.
8062 */
8063 if (node->_private == define) {
8064 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008065 if (ctxt->errNr != 0) {
8066 while ((ctxt->err != NULL) &&
8067 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8068 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
8069 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8070 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8071 xmlRelaxNGValidErrorPop(ctxt);
8072 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008073 break;
8074 }
8075
8076 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8077 if (ret <= 0) {
8078 ret = -1;
8079 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8080 xmlRelaxNGDumpValidError(ctxt);
8081 break;
8082 }
8083 ret = 0;
8084 if (ctxt->errNr != 0) {
8085 while ((ctxt->err != NULL) &&
8086 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8087 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
8088 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8089 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8090 xmlRelaxNGValidErrorPop(ctxt);
8091 }
8092 errNr = ctxt->errNr;
8093
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008094 oldflags = ctxt->flags;
8095 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8096 ctxt->flags -= FLAGS_MIXED_CONTENT;
8097 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008098 state = xmlRelaxNGNewValidState(ctxt, node);
8099 if (state == NULL) {
8100 ret = -1;
8101 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8102 xmlRelaxNGDumpValidError(ctxt);
8103 break;
8104 }
8105
8106 oldstate = ctxt->state;
8107 ctxt->state = state;
8108 if (define->attrs != NULL) {
8109 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8110 if (tmp != 0) {
8111 ret = -1;
8112 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8113 }
8114 }
8115 if (define->content != NULL) {
8116 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8117 if (tmp != 0) {
8118 ret = -1;
8119 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8120 }
8121 }
8122 if (ctxt->states != NULL) {
8123 tmp = -1;
8124
Daniel Veillardfd573f12003-03-16 17:52:32 +00008125 ctxt->flags |= FLAGS_IGNORABLE;
8126
8127 for (i = 0;i < ctxt->states->nbState;i++) {
8128 state = ctxt->states->tabState[i];
8129 ctxt->state = state;
8130
8131 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8132 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008133 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008134 }
8135 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8136 ctxt->flags = oldflags;
8137 ctxt->states = NULL;
8138 if ((ret == 0) && (tmp == -1))
8139 ret = -1;
8140 } else {
8141 state = ctxt->state;
8142 if (ret == 0)
8143 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008144 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008145 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008146 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008147 ctxt->state = oldstate;
8148 if (oldstate != NULL)
8149 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8150 if (ret == 0) {
8151 node->_private = define;
8152 }
8153 if (ret != 0) {
8154 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8155 xmlRelaxNGDumpValidError(ctxt);
8156 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008157 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008158 }
8159
8160#ifdef DEBUG
8161 xmlGenericError(xmlGenericErrorContext,
8162 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8163 node->name, ret);
8164 if (oldstate == NULL)
8165 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8166 else if (oldstate->seq == NULL)
8167 xmlGenericError(xmlGenericErrorContext, ": done\n");
8168 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8169 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8170 oldstate->seq->name);
8171 else
8172 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8173 oldstate->seq->name, oldstate->seq->type);
8174#endif
8175 break;
8176 case XML_RELAXNG_OPTIONAL: {
8177 oldflags = ctxt->flags;
8178 ctxt->flags |= FLAGS_IGNORABLE;
8179 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8180 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8181 if (ret != 0) {
8182 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008183 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008184 ctxt->state = oldstate;
8185 ctxt->flags = oldflags;
8186 ret = 0;
8187 break;
8188 }
8189 if (ctxt->states != NULL) {
8190 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8191 } else {
8192 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8193 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008194 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008195 ctxt->flags = oldflags;
8196 ret = -1;
8197 break;
8198 }
8199 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8200 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8201 ctxt->state = NULL;
8202 }
8203 ctxt->flags = oldflags;
8204 ret = 0;
8205 break;
8206 }
8207 case XML_RELAXNG_ONEORMORE:
8208 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8209 if (ret != 0) {
8210 break;
8211 }
8212 /* no break on purpose */
8213 case XML_RELAXNG_ZEROORMORE: {
8214 int progress;
8215 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8216 int base, j;
8217
8218 res = xmlRelaxNGNewStates(ctxt, 1);
8219 if (res == NULL) {
8220 ret = -1;
8221 break;
8222 }
8223 /*
8224 * All the input states are also exit states
8225 */
8226 if (ctxt->state != NULL) {
8227 xmlRelaxNGAddStates(ctxt, res,
8228 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8229 } else {
8230 for (j = 0;j < ctxt->states->nbState;j++) {
8231 xmlRelaxNGAddStates(ctxt, res,
8232 xmlRelaxNGCopyValidState(ctxt,
8233 ctxt->states->tabState[j]));
8234 }
8235 }
8236 oldflags = ctxt->flags;
8237 ctxt->flags |= FLAGS_IGNORABLE;
8238 do {
8239 progress = 0;
8240 base = res->nbState;
8241
8242 if (ctxt->states != NULL) {
8243 states = ctxt->states;
8244 for (i = 0;i < states->nbState;i++) {
8245 ctxt->state = states->tabState[i];
8246 ctxt->states = NULL;
8247 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8248 define->content);
8249 if (ret == 0) {
8250 if (ctxt->state != NULL) {
8251 tmp = xmlRelaxNGAddStates(ctxt, res,
8252 ctxt->state);
8253 ctxt->state = NULL;
8254 if (tmp == 1)
8255 progress = 1;
8256 } else if (ctxt->states != NULL) {
8257 for (j = 0;j < ctxt->states->nbState;j++) {
8258 tmp = xmlRelaxNGAddStates(ctxt, res,
8259 ctxt->states->tabState[j]);
8260 if (tmp == 1)
8261 progress = 1;
8262 }
8263 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8264 ctxt->states = NULL;
8265 }
8266 } else {
8267 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008268 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008269 ctxt->state = NULL;
8270 }
8271 }
8272 }
8273 } else {
8274 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8275 define->content);
8276 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008277 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008278 ctxt->state = NULL;
8279 } else {
8280 base = res->nbState;
8281 if (ctxt->state != NULL) {
8282 tmp = xmlRelaxNGAddStates(ctxt, res,
8283 ctxt->state);
8284 ctxt->state = NULL;
8285 if (tmp == 1)
8286 progress = 1;
8287 } else if (ctxt->states != NULL) {
8288 for (j = 0;j < ctxt->states->nbState;j++) {
8289 tmp = xmlRelaxNGAddStates(ctxt, res,
8290 ctxt->states->tabState[j]);
8291 if (tmp == 1)
8292 progress = 1;
8293 }
8294 if (states == NULL) {
8295 states = ctxt->states;
8296 } else {
8297 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8298 }
8299 ctxt->states = NULL;
8300 }
8301 }
8302 }
8303 if (progress) {
8304 /*
8305 * Collect all the new nodes added at that step
8306 * and make them the new node set
8307 */
8308 if (res->nbState - base == 1) {
8309 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8310 res->tabState[base]);
8311 } else {
8312 if (states == NULL) {
8313 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8314 }
8315 states->nbState = 0;
8316 for (i = base;i < res->nbState;i++)
8317 xmlRelaxNGAddStates(ctxt, states,
8318 xmlRelaxNGCopyValidState(ctxt,
8319 res->tabState[i]));
8320 ctxt->states = states;
8321 }
8322 }
8323 } while (progress == 1);
8324 if (states != NULL) {
8325 xmlRelaxNGFreeStates(ctxt, states);
8326 }
8327 ctxt->states = res;
8328 ctxt->flags = oldflags;
8329 ret = 0;
8330 break;
8331 }
8332 case XML_RELAXNG_CHOICE: {
8333 xmlRelaxNGDefinePtr list = define->content;
8334 xmlRelaxNGStatesPtr states = NULL;
8335
8336
8337 oldflags = ctxt->flags;
8338 errNr = ctxt->errNr;
8339 ctxt->flags |= FLAGS_IGNORABLE;
8340 node = xmlRelaxNGSkipIgnored(ctxt, node);
8341
8342 while (list != NULL) {
8343 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8344 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8345 if (ret == 0) {
8346 if (states == NULL) {
8347 states = xmlRelaxNGNewStates(ctxt, 1);
8348 }
8349 if (ctxt->state != NULL) {
8350 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8351 } else if (ctxt->states != NULL) {
8352 for (i = 0;i < ctxt->states->nbState;i++) {
8353 xmlRelaxNGAddStates(ctxt, states,
8354 ctxt->states->tabState[i]);
8355 }
8356 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8357 ctxt->states = NULL;
8358 }
8359 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008360 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008361 }
8362 ctxt->state = oldstate;
8363 list = list->next;
8364 }
8365 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008366 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008367 ctxt->states = states;
8368 ctxt->state = NULL;
8369 ret = 0;
8370 } else {
8371 ctxt->states = NULL;
8372 }
8373 ctxt->flags = oldflags;
8374 if (ret != 0) {
8375 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8376 xmlRelaxNGDumpValidError(ctxt);
8377 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008378 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008379 }
8380 break;
8381 }
8382 case XML_RELAXNG_DEF:
8383 case XML_RELAXNG_GROUP:
8384 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008385 break;
8386 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008387 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008388 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008389 case XML_RELAXNG_ATTRIBUTE:
8390 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8391 break;
8392 case XML_RELAXNG_NOOP:
8393 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008394 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008395 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8396 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008397 case XML_RELAXNG_PARENTREF:
8398 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8399 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008400 case XML_RELAXNG_DATATYPE: {
8401 xmlNodePtr child;
8402 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008403
Daniel Veillardfd573f12003-03-16 17:52:32 +00008404 child = node;
8405 while (child != NULL) {
8406 if (child->type == XML_ELEMENT_NODE) {
8407 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8408 node->parent->name);
8409 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008410 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008411 } else if ((child->type == XML_TEXT_NODE) ||
8412 (child->type == XML_CDATA_SECTION_NODE)) {
8413 content = xmlStrcat(content, child->content);
8414 }
8415 /* TODO: handle entities ... */
8416 child = child->next;
8417 }
8418 if (ret == -1) {
8419 if (content != NULL)
8420 xmlFree(content);
8421 break;
8422 }
8423 if (content == NULL) {
8424 content = xmlStrdup(BAD_CAST "");
8425 if (content == NULL) {
8426 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8427 ret = -1;
8428 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008429 }
8430 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008431 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8432 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008433 if (ret == -1) {
8434 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8435 } else if (ret == 0) {
8436 ctxt->state->seq = NULL;
8437 }
8438 if (content != NULL)
8439 xmlFree(content);
8440 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008441 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008442 case XML_RELAXNG_VALUE: {
8443 xmlChar *content = NULL;
8444 xmlChar *oldvalue;
8445 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008446
Daniel Veillardfd573f12003-03-16 17:52:32 +00008447 child = node;
8448 while (child != NULL) {
8449 if (child->type == XML_ELEMENT_NODE) {
8450 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8451 node->parent->name);
8452 ret = -1;
8453 break;
8454 } else if ((child->type == XML_TEXT_NODE) ||
8455 (child->type == XML_CDATA_SECTION_NODE)) {
8456 content = xmlStrcat(content, child->content);
8457 }
8458 /* TODO: handle entities ... */
8459 child = child->next;
8460 }
8461 if (ret == -1) {
8462 if (content != NULL)
8463 xmlFree(content);
8464 break;
8465 }
8466 if (content == NULL) {
8467 content = xmlStrdup(BAD_CAST "");
8468 if (content == NULL) {
8469 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8470 ret = -1;
8471 break;
8472 }
8473 }
8474 oldvalue = ctxt->state->value;
8475 ctxt->state->value = content;
8476 ret = xmlRelaxNGValidateValue(ctxt, define);
8477 ctxt->state->value = oldvalue;
8478 if (ret == -1) {
8479 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8480 } else if (ret == 0) {
8481 ctxt->state->seq = NULL;
8482 }
8483 if (content != NULL)
8484 xmlFree(content);
8485 break;
8486 }
8487 case XML_RELAXNG_LIST: {
8488 xmlChar *content;
8489 xmlNodePtr child;
8490 xmlChar *oldvalue, *oldendvalue;
8491 int len;
8492
8493 /*
8494 * Make sure it's only text nodes
8495 */
8496
8497 content = NULL;
8498 child = node;
8499 while (child != NULL) {
8500 if (child->type == XML_ELEMENT_NODE) {
8501 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8502 node->parent->name);
8503 ret = -1;
8504 break;
8505 } else if ((child->type == XML_TEXT_NODE) ||
8506 (child->type == XML_CDATA_SECTION_NODE)) {
8507 content = xmlStrcat(content, child->content);
8508 }
8509 /* TODO: handle entities ... */
8510 child = child->next;
8511 }
8512 if (ret == -1) {
8513 if (content != NULL)
8514 xmlFree(content);
8515 break;
8516 }
8517 if (content == NULL) {
8518 content = xmlStrdup(BAD_CAST "");
8519 if (content == NULL) {
8520 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8521 ret = -1;
8522 break;
8523 }
8524 }
8525 len = xmlStrlen(content);
8526 oldvalue = ctxt->state->value;
8527 oldendvalue = ctxt->state->endvalue;
8528 ctxt->state->value = content;
8529 ctxt->state->endvalue = content + len;
8530 ret = xmlRelaxNGValidateValue(ctxt, define);
8531 ctxt->state->value = oldvalue;
8532 ctxt->state->endvalue = oldendvalue;
8533 if (ret == -1) {
8534 VALID_ERR(XML_RELAXNG_ERR_LIST);
8535 } else if ((ret == 0) && (node != NULL)) {
8536 ctxt->state->seq = node->next;
8537 }
8538 if (content != NULL)
8539 xmlFree(content);
8540 break;
8541 }
8542 case XML_RELAXNG_START:
8543 case XML_RELAXNG_EXCEPT:
8544 case XML_RELAXNG_PARAM:
8545 TODO
8546 ret = -1;
8547 break;
8548 }
8549 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008550#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008551 for (i = 0;i < ctxt->depth;i++)
8552 xmlGenericError(xmlGenericErrorContext, " ");
8553 xmlGenericError(xmlGenericErrorContext,
8554 "Validating %s ", xmlRelaxNGDefName(define));
8555 if (define->name != NULL)
8556 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8557 if (ret == 0)
8558 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8559 else
8560 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008561#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008562 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008563}
8564
8565/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008566 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008567 * @ctxt: a Relax-NG validation context
8568 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008569 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008570 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008571 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008572 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008573 */
8574static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008575xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8576 xmlRelaxNGDefinePtr define) {
8577 xmlRelaxNGStatesPtr states, res;
8578 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008579
Daniel Veillardfd573f12003-03-16 17:52:32 +00008580 /*
8581 * We should NOT have both ctxt->state and ctxt->states
8582 */
8583 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8584 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008585 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008586 ctxt->state = NULL;
8587 }
8588
8589 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8590 if (ctxt->states != NULL) {
8591 ctxt->state = ctxt->states->tabState[0];
8592 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8593 ctxt->states = NULL;
8594 }
8595 ret = xmlRelaxNGValidateState(ctxt, define);
8596 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8597 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008598 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008599 ctxt->state = NULL;
8600 }
8601 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8602 ctxt->state = ctxt->states->tabState[0];
8603 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8604 ctxt->states = NULL;
8605 }
8606 return(ret);
8607 }
8608
8609 states = ctxt->states;
8610 ctxt->states = NULL;
8611 res = NULL;
8612 j = 0;
8613 oldflags = ctxt->flags;
8614 ctxt->flags |= FLAGS_IGNORABLE;
8615 for (i = 0;i < states->nbState;i++) {
8616 ctxt->state = states->tabState[i];
8617 ctxt->states = NULL;
8618 ret = xmlRelaxNGValidateState(ctxt, define);
8619 /*
8620 * We should NOT have both ctxt->state and ctxt->states
8621 */
8622 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8623 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008624 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008625 ctxt->state = NULL;
8626 }
8627 if (ret == 0) {
8628 if (ctxt->states == NULL) {
8629 if (res != NULL) {
8630 /* add the state to the container */
8631 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8632 ctxt->state = NULL;
8633 } else {
8634 /* add the state directly in states */
8635 states->tabState[j++] = ctxt->state;
8636 ctxt->state = NULL;
8637 }
8638 } else {
8639 if (res == NULL) {
8640 /* make it the new container and copy other results */
8641 res = ctxt->states;
8642 ctxt->states = NULL;
8643 for (k = 0;k < j;k++)
8644 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8645 } else {
8646 /* add all the new results to res and reff the container */
8647 for (k = 0;k < ctxt->states->nbState;k++)
8648 xmlRelaxNGAddStates(ctxt, res,
8649 ctxt->states->tabState[k]);
8650 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8651 ctxt->states = NULL;
8652 }
8653 }
8654 } else {
8655 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008656 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008657 ctxt->state = NULL;
8658 } else if (ctxt->states != NULL) {
8659 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008660 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008661 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8662 ctxt->states = NULL;
8663 }
8664 }
8665 }
8666 ctxt->flags = oldflags;
8667 if (res != NULL) {
8668 xmlRelaxNGFreeStates(ctxt, states);
8669 ctxt->states = res;
8670 ret = 0;
8671 } else if (j > 1) {
8672 states->nbState = j;
8673 ctxt->states = states;
8674 ret =0;
8675 } else if (j == 1) {
8676 ctxt->state = states->tabState[0];
8677 xmlRelaxNGFreeStates(ctxt, states);
8678 ret = 0;
8679 } else {
8680 ret = -1;
8681 xmlRelaxNGFreeStates(ctxt, states);
8682 if (ctxt->states != NULL) {
8683 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8684 ctxt->states = NULL;
8685 }
8686 }
8687 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8688 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008689 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008690 ctxt->state = NULL;
8691 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008692 return(ret);
8693}
8694
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008695/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008696 * xmlRelaxNGValidateDocument:
8697 * @ctxt: a Relax-NG validation context
8698 * @doc: the document
8699 *
8700 * Validate the given document
8701 *
8702 * Returns 0 if the validation succeeded or an error code.
8703 */
8704static int
8705xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8706 int ret;
8707 xmlRelaxNGPtr schema;
8708 xmlRelaxNGGrammarPtr grammar;
8709 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008710 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008711
8712 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8713 return(-1);
8714
8715 schema = ctxt->schema;
8716 grammar = schema->topgrammar;
8717 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008718 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008719 return(-1);
8720 }
8721 state = xmlRelaxNGNewValidState(ctxt, NULL);
8722 ctxt->state = state;
8723 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008724 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8725 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008726 node = state->seq;
8727 node = xmlRelaxNGSkipIgnored(ctxt, node);
8728 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008729 if (ret != -1) {
8730 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8731 ret = -1;
8732 }
8733 }
8734 } else if (ctxt->states != NULL) {
8735 int i;
8736 int tmp = -1;
8737
8738 for (i = 0;i < ctxt->states->nbState;i++) {
8739 state = ctxt->states->tabState[i];
8740 node = state->seq;
8741 node = xmlRelaxNGSkipIgnored(ctxt, node);
8742 if (node == NULL)
8743 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008744 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008745 }
8746 if (tmp == -1) {
8747 if (ret != -1) {
8748 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8749 ret = -1;
8750 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008751 }
8752 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008753 if (ctxt->state != NULL) {
8754 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8755 ctxt->state = NULL;
8756 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008757 if (ret != 0)
8758 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008759 if (ctxt->idref == 1) {
8760 xmlValidCtxt vctxt;
8761
8762 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8763 vctxt.valid = 1;
8764 vctxt.error = ctxt->error;
8765 vctxt.warning = ctxt->warning;
8766 vctxt.userData = ctxt->userData;
8767
8768 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8769 ret = -1;
8770 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008771
8772 return(ret);
8773}
8774
Daniel Veillardfd573f12003-03-16 17:52:32 +00008775/************************************************************************
8776 * *
8777 * Validation interfaces *
8778 * *
8779 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008780/**
8781 * xmlRelaxNGNewValidCtxt:
8782 * @schema: a precompiled XML RelaxNGs
8783 *
8784 * Create an XML RelaxNGs validation context based on the given schema
8785 *
8786 * Returns the validation context or NULL in case of error
8787 */
8788xmlRelaxNGValidCtxtPtr
8789xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8790 xmlRelaxNGValidCtxtPtr ret;
8791
8792 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8793 if (ret == NULL) {
8794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008795 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008796 return (NULL);
8797 }
8798 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8799 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008800 ret->error = xmlGenericError;
8801 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008802 ret->errNr = 0;
8803 ret->errMax = 0;
8804 ret->err = NULL;
8805 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008806 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00008807 ret->states = NULL;
8808 ret->freeState = NULL;
8809 ret->freeStates = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008810 return (ret);
8811}
8812
8813/**
8814 * xmlRelaxNGFreeValidCtxt:
8815 * @ctxt: the schema validation context
8816 *
8817 * Free the resources associated to the schema validation context
8818 */
8819void
8820xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008821 int k;
8822
Daniel Veillard6eadf632003-01-23 18:29:16 +00008823 if (ctxt == NULL)
8824 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008825 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008826 xmlRelaxNGFreeStates(NULL, ctxt->states);
8827 if (ctxt->freeState != NULL) {
8828 for (k = 0;k < ctxt->freeState->nbState;k++) {
8829 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
8830 }
8831 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
8832 }
Daniel Veillard798024a2003-03-19 10:36:09 +00008833 if (ctxt->freeStates != NULL) {
8834 for (k = 0;k < ctxt->freeStatesNr;k++) {
8835 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
8836 }
8837 xmlFree(ctxt->freeStates);
8838 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00008839 if (ctxt->errTab != NULL)
8840 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008841 xmlFree(ctxt);
8842}
8843
8844/**
8845 * xmlRelaxNGSetValidErrors:
8846 * @ctxt: a Relax-NG validation context
8847 * @err: the error function
8848 * @warn: the warning function
8849 * @ctx: the functions context
8850 *
8851 * Set the error and warning callback informations
8852 */
8853void
8854xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8855 xmlRelaxNGValidityErrorFunc err,
8856 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8857 if (ctxt == NULL)
8858 return;
8859 ctxt->error = err;
8860 ctxt->warning = warn;
8861 ctxt->userData = ctx;
8862}
8863
8864/**
8865 * xmlRelaxNGValidateDoc:
8866 * @ctxt: a Relax-NG validation context
8867 * @doc: a parsed document tree
8868 *
8869 * Validate a document tree in memory.
8870 *
8871 * Returns 0 if the document is valid, a positive error code
8872 * number otherwise and -1 in case of internal or API error.
8873 */
8874int
8875xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8876 int ret;
8877
8878 if ((ctxt == NULL) || (doc == NULL))
8879 return(-1);
8880
8881 ctxt->doc = doc;
8882
8883 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00008884 /*
8885 * TODO: build error codes
8886 */
8887 if (ret == -1)
8888 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008889 return(ret);
8890}
8891
8892#endif /* LIBXML_SCHEMAS_ENABLED */
8893