relaxng.c revision 81c51e174df3095c2b7bb590fc070165d7a6ac9e
1/*
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
9/**
10 * TODO:
11 * - add support for DTD compatibility spec
12 *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
13 * - report better mem allocations pbms at runtime and abort immediately.
14 */
15
16#define IN_LIBXML
17#include "libxml.h"
18
19#ifdef LIBXML_SCHEMAS_ENABLED
20
21#include <string.h>
22#include <stdio.h>
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25#include <libxml/parserInternals.h>
26#include <libxml/hash.h>
27#include <libxml/uri.h>
28
29#include <libxml/relaxng.h>
30
31#include <libxml/xmlschemastypes.h>
32#include <libxml/xmlautomata.h>
33#include <libxml/xmlregexp.h>
34#include <libxml/xmlschemastypes.h>
35
36/*
37 * The Relax-NG namespace
38 */
39static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40    "http://relaxng.org/ns/structure/1.0";
41
42#define IS_RELAXNG(node, type)						\
43   ((node != NULL) && (node->ns != NULL) &&				\
44    (xmlStrEqual(node->name, (const xmlChar *) type)) &&		\
45    (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
46
47
48#if 0
49#define DEBUG 1
50
51#define DEBUG_GRAMMAR 1
52
53#define DEBUG_CONTENT 1
54
55#define DEBUG_TYPE 1
56
57#define DEBUG_VALID 1
58
59#define DEBUG_INTERLEAVE 1
60
61#define DEBUG_LIST 1
62
63#define DEBUG_INCLUDE 1
64
65#define DEBUG_ERROR 1
66
67#define DEBUG_COMPILE 1
68
69#define DEBUG_PROGRESSIVE 1
70#endif
71
72#define MAX_ERROR 5
73
74#define TODO 								\
75    xmlGenericError(xmlGenericErrorContext,				\
76	    "Unimplemented block at %s:%d\n",				\
77            __FILE__, __LINE__);
78
79typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
80typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
81
82typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
83typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
84
85typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
86typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
87
88typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
89typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
90
91typedef enum {
92    XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
93    XML_RELAXNG_COMBINE_CHOICE, /* choice */
94    XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
95} xmlRelaxNGCombine;
96
97typedef enum {
98    XML_RELAXNG_CONTENT_ERROR = -1,
99    XML_RELAXNG_CONTENT_EMPTY = 0,
100    XML_RELAXNG_CONTENT_SIMPLE,
101    XML_RELAXNG_CONTENT_COMPLEX
102} xmlRelaxNGContentType;
103
104typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
105typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
106
107struct _xmlRelaxNGGrammar {
108    xmlRelaxNGGrammarPtr parent;        /* the parent grammar if any */
109    xmlRelaxNGGrammarPtr children;      /* the children grammar if any */
110    xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
111    xmlRelaxNGDefinePtr start;  /* <start> content */
112    xmlRelaxNGCombine combine;  /* the default combine value */
113    xmlRelaxNGDefinePtr startList;      /* list of <start> definitions */
114    xmlHashTablePtr defs;       /* define* */
115    xmlHashTablePtr refs;       /* references */
116};
117
118
119typedef enum {
120    XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
121    XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
122    XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
123    XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
124    XML_RELAXNG_TEXT,           /* textual content */
125    XML_RELAXNG_ELEMENT,        /* an element */
126    XML_RELAXNG_DATATYPE,       /* extenal data type definition */
127    XML_RELAXNG_PARAM,          /* extenal data type parameter */
128    XML_RELAXNG_VALUE,          /* value from an extenal data type definition */
129    XML_RELAXNG_LIST,           /* a list of patterns */
130    XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */
131    XML_RELAXNG_DEF,            /* a definition */
132    XML_RELAXNG_REF,            /* reference to a definition */
133    XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
134    XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
135    XML_RELAXNG_OPTIONAL,       /* optional patterns */
136    XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
137    XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
138    XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
139    XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
140    XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
141    XML_RELAXNG_START           /* Used to keep track of starts on grammars */
142} xmlRelaxNGType;
143
144#define IS_NULLABLE		(1 << 0)
145#define IS_NOT_NULLABLE		(1 << 1)
146#define IS_INDETERMINIST	(1 << 2)
147#define IS_MIXED		(1 << 3)
148#define IS_TRIABLE		(1 << 4)
149#define IS_PROCESSED		(1 << 5)
150#define IS_COMPILABLE		(1 << 6)
151#define IS_NOT_COMPILABLE	(1 << 7)
152
153struct _xmlRelaxNGDefine {
154    xmlRelaxNGType type;        /* the type of definition */
155    xmlNodePtr node;            /* the node in the source */
156    xmlChar *name;              /* the element local name if present */
157    xmlChar *ns;                /* the namespace local name if present */
158    xmlChar *value;             /* value when available */
159    void *data;                 /* data lib or specific pointer */
160    xmlRelaxNGDefinePtr content;        /* the expected content */
161    xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
162    xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
163    xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
164    xmlRelaxNGDefinePtr nameClass;      /* the nameClass definition if any */
165    xmlRelaxNGDefinePtr nextHash;       /* next define in defs/refs hash tables */
166    short depth;                /* used for the cycle detection */
167    short dflags;               /* define related flags */
168    xmlRegexpPtr contModel;     /* a compiled content model if available */
169};
170
171/**
172 * _xmlRelaxNG:
173 *
174 * A RelaxNGs definition
175 */
176struct _xmlRelaxNG {
177    void *_private;             /* unused by the library for users or bindings */
178    xmlRelaxNGGrammarPtr topgrammar;
179    xmlDocPtr doc;
180
181    int idref;                  /* requires idref checking */
182
183    xmlHashTablePtr defs;       /* define */
184    xmlHashTablePtr refs;       /* references */
185    xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
186    xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
187    int defNr;                  /* number of defines used */
188    xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
189
190};
191
192#define XML_RELAXNG_IN_ATTRIBUTE	(1 << 0)
193#define XML_RELAXNG_IN_ONEORMORE	(1 << 1)
194#define XML_RELAXNG_IN_LIST		(1 << 2)
195#define XML_RELAXNG_IN_DATAEXCEPT	(1 << 3)
196#define XML_RELAXNG_IN_START		(1 << 4)
197#define XML_RELAXNG_IN_OOMGROUP		(1 << 5)
198#define XML_RELAXNG_IN_OOMINTERLEAVE	(1 << 6)
199#define XML_RELAXNG_IN_EXTERNALREF	(1 << 7)
200#define XML_RELAXNG_IN_ANYEXCEPT	(1 << 8)
201#define XML_RELAXNG_IN_NSEXCEPT		(1 << 9)
202
203struct _xmlRelaxNGParserCtxt {
204    void *userData;             /* user specific data block */
205    xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
206    xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
207    xmlStructuredErrorFunc serror;
208    xmlRelaxNGValidErr err;
209
210    xmlRelaxNGPtr schema;       /* The schema in use */
211    xmlRelaxNGGrammarPtr grammar;       /* the current grammar */
212    xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
213    int flags;                  /* parser flags */
214    int nbErrors;               /* number of errors at parse time */
215    int nbWarnings;             /* number of warnings at parse time */
216    const xmlChar *define;      /* the current define scope */
217    xmlRelaxNGDefinePtr def;    /* the current define */
218
219    int nbInterleaves;
220    xmlHashTablePtr interleaves;        /* keep track of all the interleaves */
221
222    xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
223    xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
224    xmlChar *URL;
225    xmlDocPtr document;
226
227    int defNr;                  /* number of defines used */
228    int defMax;                 /* number of defines aloocated */
229    xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
230
231    const char *buffer;
232    int size;
233
234    /* the document stack */
235    xmlRelaxNGDocumentPtr doc;  /* Current parsed external ref */
236    int docNr;                  /* Depth of the parsing stack */
237    int docMax;                 /* Max depth of the parsing stack */
238    xmlRelaxNGDocumentPtr *docTab;      /* array of docs */
239
240    /* the include stack */
241    xmlRelaxNGIncludePtr inc;   /* Current parsed include */
242    int incNr;                  /* Depth of the include parsing stack */
243    int incMax;                 /* Max depth of the parsing stack */
244    xmlRelaxNGIncludePtr *incTab;       /* array of incs */
245
246    int idref;                  /* requires idref checking */
247
248    /* used to compile content models */
249    xmlAutomataPtr am;          /* the automata */
250    xmlAutomataStatePtr state;  /* used to build the automata */
251
252    int crng;			/* compact syntax and other flags */
253    int freedoc;		/* need to free the document */
254};
255
256#define FLAGS_IGNORABLE		1
257#define FLAGS_NEGATIVE		2
258#define FLAGS_MIXED_CONTENT	4
259#define FLAGS_NOERROR		8
260
261/**
262 * xmlRelaxNGInterleaveGroup:
263 *
264 * A RelaxNGs partition set associated to lists of definitions
265 */
266typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
267typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
268struct _xmlRelaxNGInterleaveGroup {
269    xmlRelaxNGDefinePtr rule;   /* the rule to satisfy */
270    xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
271    xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
272};
273
274#define IS_DETERMINIST		1
275#define IS_NEEDCHECK		2
276
277/**
278 * xmlRelaxNGPartitions:
279 *
280 * A RelaxNGs partition associated to an interleave group
281 */
282typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
283typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
284struct _xmlRelaxNGPartition {
285    int nbgroups;               /* number of groups in the partitions */
286    xmlHashTablePtr triage;     /* hash table used to direct nodes to the
287                                 * right group when possible */
288    int flags;                  /* determinist ? */
289    xmlRelaxNGInterleaveGroupPtr *groups;
290};
291
292/**
293 * xmlRelaxNGValidState:
294 *
295 * A RelaxNGs validation state
296 */
297#define MAX_ATTR 20
298typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
299typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
300struct _xmlRelaxNGValidState {
301    xmlNodePtr node;            /* the current node */
302    xmlNodePtr seq;             /* the sequence of children left to validate */
303    int nbAttrs;                /* the number of attributes */
304    int maxAttrs;               /* the size of attrs */
305    int nbAttrLeft;             /* the number of attributes left to validate */
306    xmlChar *value;             /* the value when operating on string */
307    xmlChar *endvalue;          /* the end value when operating on string */
308    xmlAttrPtr *attrs;          /* the array of attributes */
309};
310
311/**
312 * xmlRelaxNGStates:
313 *
314 * A RelaxNGs container for validation state
315 */
316typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
317typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
318struct _xmlRelaxNGStates {
319    int nbState;                /* the number of states */
320    int maxState;               /* the size of the array */
321    xmlRelaxNGValidStatePtr *tabState;
322};
323
324#define ERROR_IS_DUP	1
325
326/**
327 * xmlRelaxNGValidError:
328 *
329 * A RelaxNGs validation error
330 */
331typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
332typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
333struct _xmlRelaxNGValidError {
334    xmlRelaxNGValidErr err;     /* the error number */
335    int flags;                  /* flags */
336    xmlNodePtr node;            /* the current node */
337    xmlNodePtr seq;             /* the current child */
338    const xmlChar *arg1;        /* first arg */
339    const xmlChar *arg2;        /* second arg */
340};
341
342/**
343 * xmlRelaxNGValidCtxt:
344 *
345 * A RelaxNGs validation context
346 */
347
348struct _xmlRelaxNGValidCtxt {
349    void *userData;             /* user specific data block */
350    xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
351    xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
352    xmlStructuredErrorFunc serror;
353    int nbErrors;               /* number of errors in validation */
354
355    xmlRelaxNGPtr schema;       /* The schema in use */
356    xmlDocPtr doc;              /* the document being validated */
357    int flags;                  /* validation flags */
358    int depth;                  /* validation depth */
359    int idref;                  /* requires idref checking */
360    int errNo;                  /* the first error found */
361
362    /*
363     * Errors accumulated in branches may have to be stacked to be
364     * provided back when it's sure they affect validation.
365     */
366    xmlRelaxNGValidErrorPtr err;        /* Last error */
367    int errNr;                  /* Depth of the error stack */
368    int errMax;                 /* Max depth of the error stack */
369    xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */
370
371    xmlRelaxNGValidStatePtr state;      /* the current validation state */
372    xmlRelaxNGStatesPtr states; /* the accumulated state list */
373
374    xmlRelaxNGStatesPtr freeState;      /* the pool of free valid states */
375    int freeStatesNr;
376    int freeStatesMax;
377    xmlRelaxNGStatesPtr *freeStates;    /* the pool of free state groups */
378
379    /*
380     * This is used for "progressive" validation
381     */
382    xmlRegExecCtxtPtr elem;     /* the current element regexp */
383    int elemNr;                 /* the number of element validated */
384    int elemMax;                /* the max depth of elements */
385    xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
386    int pstate;                 /* progressive state */
387    xmlNodePtr pnode;           /* the current node */
388    xmlRelaxNGDefinePtr pdef;   /* the non-streamable definition */
389    int perr;                   /* signal error in content model
390                                 * outside the regexp */
391};
392
393/**
394 * xmlRelaxNGInclude:
395 *
396 * Structure associated to a RelaxNGs document element
397 */
398struct _xmlRelaxNGInclude {
399    xmlRelaxNGIncludePtr next;  /* keep a chain of includes */
400    xmlChar *href;              /* the normalized href value */
401    xmlDocPtr doc;              /* the associated XML document */
402    xmlRelaxNGDefinePtr content;        /* the definitions */
403    xmlRelaxNGPtr schema;       /* the schema */
404};
405
406/**
407 * xmlRelaxNGDocument:
408 *
409 * Structure associated to a RelaxNGs document element
410 */
411struct _xmlRelaxNGDocument {
412    xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
413    xmlChar *href;              /* the normalized href value */
414    xmlDocPtr doc;              /* the associated XML document */
415    xmlRelaxNGDefinePtr content;        /* the definitions */
416    xmlRelaxNGPtr schema;       /* the schema */
417    int externalRef;            /* 1 if an external ref */
418};
419
420
421/************************************************************************
422 *									*
423 * 		Some factorized error routines				*
424 *									*
425 ************************************************************************/
426
427/**
428 * xmlRngPErrMemory:
429 * @ctxt:  an Relax-NG parser context
430 * @extra:  extra informations
431 *
432 * Handle a redefinition of attribute error
433 */
434static void
435xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
436{
437    xmlStructuredErrorFunc schannel = NULL;
438    xmlGenericErrorFunc channel = NULL;
439    void *data = NULL;
440
441    if (ctxt != NULL) {
442        if (ctxt->serror != NULL)
443	    schannel = ctxt->serror;
444	else
445	    channel = ctxt->error;
446        data = ctxt->userData;
447        ctxt->nbErrors++;
448    }
449    if (extra)
450        __xmlRaiseError(schannel, channel, data,
451                        NULL, NULL, XML_FROM_RELAXNGP,
452                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
453                        NULL, NULL, 0, 0,
454                        "Memory allocation failed : %s\n", extra);
455    else
456        __xmlRaiseError(schannel, channel, data,
457                        NULL, NULL, XML_FROM_RELAXNGP,
458                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
459                        NULL, NULL, 0, 0, "Memory allocation failed\n");
460}
461
462/**
463 * xmlRngVErrMemory:
464 * @ctxt:  a Relax-NG validation context
465 * @extra:  extra informations
466 *
467 * Handle a redefinition of attribute error
468 */
469static void
470xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
471{
472    xmlStructuredErrorFunc schannel = NULL;
473    xmlGenericErrorFunc channel = NULL;
474    void *data = NULL;
475
476    if (ctxt != NULL) {
477        if (ctxt->serror != NULL)
478	    schannel = ctxt->serror;
479	else
480	    channel = ctxt->error;
481        data = ctxt->userData;
482        ctxt->nbErrors++;
483    }
484    if (extra)
485        __xmlRaiseError(schannel, channel, data,
486                        NULL, NULL, XML_FROM_RELAXNGV,
487                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
488                        NULL, NULL, 0, 0,
489                        "Memory allocation failed : %s\n", extra);
490    else
491        __xmlRaiseError(schannel, channel, data,
492                        NULL, NULL, XML_FROM_RELAXNGV,
493                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
494                        NULL, NULL, 0, 0, "Memory allocation failed\n");
495}
496
497/**
498 * xmlRngPErr:
499 * @ctxt:  a Relax-NG parser context
500 * @node:  the node raising the error
501 * @error:  the error code
502 * @msg:  message
503 * @str1:  extra info
504 * @str2:  extra info
505 *
506 * Handle a Relax NG Parsing error
507 */
508static void
509xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
510           const char *msg, const xmlChar * str1, const xmlChar * str2)
511{
512    xmlStructuredErrorFunc schannel = NULL;
513    xmlGenericErrorFunc channel = NULL;
514    void *data = NULL;
515
516    if (ctxt != NULL) {
517        if (ctxt->serror != NULL)
518	    schannel = ctxt->serror;
519	else
520	    channel = ctxt->error;
521        data = ctxt->userData;
522        ctxt->nbErrors++;
523    }
524    __xmlRaiseError(schannel, channel, data,
525                    NULL, node, XML_FROM_RELAXNGP,
526                    error, XML_ERR_ERROR, NULL, 0,
527                    (const char *) str1, (const char *) str2, NULL, 0, 0,
528                    msg, str1, str2);
529}
530
531/**
532 * xmlRngVErr:
533 * @ctxt:  a Relax-NG validation context
534 * @node:  the node raising the error
535 * @error:  the error code
536 * @msg:  message
537 * @str1:  extra info
538 * @str2:  extra info
539 *
540 * Handle a Relax NG Validation error
541 */
542static void
543xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
544           const char *msg, const xmlChar * str1, const xmlChar * str2)
545{
546    xmlStructuredErrorFunc schannel = NULL;
547    xmlGenericErrorFunc channel = NULL;
548    void *data = NULL;
549
550    if (ctxt != NULL) {
551        if (ctxt->serror != NULL)
552	    schannel = ctxt->serror;
553	else
554	    channel = ctxt->error;
555        data = ctxt->userData;
556        ctxt->nbErrors++;
557    }
558    __xmlRaiseError(schannel, channel, data,
559                    NULL, node, XML_FROM_RELAXNGV,
560                    error, XML_ERR_ERROR, NULL, 0,
561                    (const char *) str1, (const char *) str2, NULL, 0, 0,
562                    msg, str1, str2);
563}
564
565/************************************************************************
566 * 									*
567 * 		Preliminary type checking interfaces			*
568 * 									*
569 ************************************************************************/
570
571/**
572 * xmlRelaxNGTypeHave:
573 * @data:  data needed for the library
574 * @type:  the type name
575 * @value:  the value to check
576 *
577 * Function provided by a type library to check if a type is exported
578 *
579 * Returns 1 if yes, 0 if no and -1 in case of error.
580 */
581typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
582
583/**
584 * xmlRelaxNGTypeCheck:
585 * @data:  data needed for the library
586 * @type:  the type name
587 * @value:  the value to check
588 * @result:  place to store the result if needed
589 *
590 * Function provided by a type library to check if a value match a type
591 *
592 * Returns 1 if yes, 0 if no and -1 in case of error.
593 */
594typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
595                                    const xmlChar * value, void **result,
596                                    xmlNodePtr node);
597
598/**
599 * xmlRelaxNGFacetCheck:
600 * @data:  data needed for the library
601 * @type:  the type name
602 * @facet:  the facet name
603 * @val:  the facet value
604 * @strval:  the string value
605 * @value:  the value to check
606 *
607 * Function provided by a type library to check a value facet
608 *
609 * Returns 1 if yes, 0 if no and -1 in case of error.
610 */
611typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
612                                     const xmlChar * facet,
613                                     const xmlChar * val,
614                                     const xmlChar * strval, void *value);
615
616/**
617 * xmlRelaxNGTypeFree:
618 * @data:  data needed for the library
619 * @result:  the value to free
620 *
621 * Function provided by a type library to free a returned result
622 */
623typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
624
625/**
626 * xmlRelaxNGTypeCompare:
627 * @data:  data needed for the library
628 * @type:  the type name
629 * @value1:  the first value
630 * @value2:  the second value
631 *
632 * Function provided by a type library to compare two values accordingly
633 * to a type.
634 *
635 * Returns 1 if yes, 0 if no and -1 in case of error.
636 */
637typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
638                                      const xmlChar * value1,
639                                      xmlNodePtr ctxt1,
640                                      void *comp1,
641                                      const xmlChar * value2,
642                                      xmlNodePtr ctxt2);
643typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
644typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
645struct _xmlRelaxNGTypeLibrary {
646    const xmlChar *namespace;   /* the datatypeLibrary value */
647    void *data;                 /* data needed for the library */
648    xmlRelaxNGTypeHave have;    /* the export function */
649    xmlRelaxNGTypeCheck check;  /* the checking function */
650    xmlRelaxNGTypeCompare comp; /* the compare function */
651    xmlRelaxNGFacetCheck facet; /* the facet check function */
652    xmlRelaxNGTypeFree freef;   /* the freeing function */
653};
654
655/************************************************************************
656 * 									*
657 * 			Allocation functions				*
658 * 									*
659 ************************************************************************/
660static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
661static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
662static void xmlRelaxNGNormExtSpace(xmlChar * value);
663static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
664static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
665                                     ATTRIBUTE_UNUSED,
666                                     xmlRelaxNGValidStatePtr state1,
667                                     xmlRelaxNGValidStatePtr state2);
668static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
669                                     xmlRelaxNGValidStatePtr state);
670
671/**
672 * xmlRelaxNGFreeDocument:
673 * @docu:  a document structure
674 *
675 * Deallocate a RelaxNG document structure.
676 */
677static void
678xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
679{
680    if (docu == NULL)
681        return;
682
683    if (docu->href != NULL)
684        xmlFree(docu->href);
685    if (docu->doc != NULL)
686        xmlFreeDoc(docu->doc);
687    if (docu->schema != NULL)
688        xmlRelaxNGFreeInnerSchema(docu->schema);
689    xmlFree(docu);
690}
691
692/**
693 * xmlRelaxNGFreeDocumentList:
694 * @docu:  a list of  document structure
695 *
696 * Deallocate a RelaxNG document structures.
697 */
698static void
699xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
700{
701    xmlRelaxNGDocumentPtr next;
702
703    while (docu != NULL) {
704        next = docu->next;
705        xmlRelaxNGFreeDocument(docu);
706        docu = next;
707    }
708}
709
710/**
711 * xmlRelaxNGFreeInclude:
712 * @incl:  a include structure
713 *
714 * Deallocate a RelaxNG include structure.
715 */
716static void
717xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
718{
719    if (incl == NULL)
720        return;
721
722    if (incl->href != NULL)
723        xmlFree(incl->href);
724    if (incl->doc != NULL)
725        xmlFreeDoc(incl->doc);
726    if (incl->schema != NULL)
727        xmlRelaxNGFree(incl->schema);
728    xmlFree(incl);
729}
730
731/**
732 * xmlRelaxNGFreeIncludeList:
733 * @incl:  a include structure list
734 *
735 * Deallocate a RelaxNG include structure.
736 */
737static void
738xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
739{
740    xmlRelaxNGIncludePtr next;
741
742    while (incl != NULL) {
743        next = incl->next;
744        xmlRelaxNGFreeInclude(incl);
745        incl = next;
746    }
747}
748
749/**
750 * xmlRelaxNGNewRelaxNG:
751 * @ctxt:  a Relax-NG validation context (optional)
752 *
753 * Allocate a new RelaxNG structure.
754 *
755 * Returns the newly allocated structure or NULL in case or error
756 */
757static xmlRelaxNGPtr
758xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
759{
760    xmlRelaxNGPtr ret;
761
762    ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
763    if (ret == NULL) {
764        xmlRngPErrMemory(ctxt, NULL);
765        return (NULL);
766    }
767    memset(ret, 0, sizeof(xmlRelaxNG));
768
769    return (ret);
770}
771
772/**
773 * xmlRelaxNGFreeInnerSchema:
774 * @schema:  a schema structure
775 *
776 * Deallocate a RelaxNG schema structure.
777 */
778static void
779xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
780{
781    if (schema == NULL)
782        return;
783
784    if (schema->doc != NULL)
785        xmlFreeDoc(schema->doc);
786    if (schema->defTab != NULL) {
787        int i;
788
789        for (i = 0; i < schema->defNr; i++)
790            xmlRelaxNGFreeDefine(schema->defTab[i]);
791        xmlFree(schema->defTab);
792    }
793
794    xmlFree(schema);
795}
796
797/**
798 * xmlRelaxNGFree:
799 * @schema:  a schema structure
800 *
801 * Deallocate a RelaxNG structure.
802 */
803void
804xmlRelaxNGFree(xmlRelaxNGPtr schema)
805{
806    if (schema == NULL)
807        return;
808
809    if (schema->topgrammar != NULL)
810        xmlRelaxNGFreeGrammar(schema->topgrammar);
811    if (schema->doc != NULL)
812        xmlFreeDoc(schema->doc);
813    if (schema->documents != NULL)
814        xmlRelaxNGFreeDocumentList(schema->documents);
815    if (schema->includes != NULL)
816        xmlRelaxNGFreeIncludeList(schema->includes);
817    if (schema->defTab != NULL) {
818        int i;
819
820        for (i = 0; i < schema->defNr; i++)
821            xmlRelaxNGFreeDefine(schema->defTab[i]);
822        xmlFree(schema->defTab);
823    }
824
825    xmlFree(schema);
826}
827
828/**
829 * xmlRelaxNGNewGrammar:
830 * @ctxt:  a Relax-NG validation context (optional)
831 *
832 * Allocate a new RelaxNG grammar.
833 *
834 * Returns the newly allocated structure or NULL in case or error
835 */
836static xmlRelaxNGGrammarPtr
837xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
838{
839    xmlRelaxNGGrammarPtr ret;
840
841    ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
842    if (ret == NULL) {
843        xmlRngPErrMemory(ctxt, NULL);
844        return (NULL);
845    }
846    memset(ret, 0, sizeof(xmlRelaxNGGrammar));
847
848    return (ret);
849}
850
851/**
852 * xmlRelaxNGFreeGrammar:
853 * @grammar:  a grammar structure
854 *
855 * Deallocate a RelaxNG grammar structure.
856 */
857static void
858xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
859{
860    if (grammar == NULL)
861        return;
862
863    if (grammar->children != NULL) {
864        xmlRelaxNGFreeGrammar(grammar->children);
865    }
866    if (grammar->next != NULL) {
867        xmlRelaxNGFreeGrammar(grammar->next);
868    }
869    if (grammar->refs != NULL) {
870        xmlHashFree(grammar->refs, NULL);
871    }
872    if (grammar->defs != NULL) {
873        xmlHashFree(grammar->defs, NULL);
874    }
875
876    xmlFree(grammar);
877}
878
879/**
880 * xmlRelaxNGNewDefine:
881 * @ctxt:  a Relax-NG validation context
882 * @node:  the node in the input document.
883 *
884 * Allocate a new RelaxNG define.
885 *
886 * Returns the newly allocated structure or NULL in case or error
887 */
888static xmlRelaxNGDefinePtr
889xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
890{
891    xmlRelaxNGDefinePtr ret;
892
893    if (ctxt->defMax == 0) {
894        ctxt->defMax = 16;
895        ctxt->defNr = 0;
896        ctxt->defTab = (xmlRelaxNGDefinePtr *)
897            xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
898        if (ctxt->defTab == NULL) {
899            xmlRngPErrMemory(ctxt, "allocating define\n");
900            return (NULL);
901        }
902    } else if (ctxt->defMax <= ctxt->defNr) {
903        xmlRelaxNGDefinePtr *tmp;
904
905        ctxt->defMax *= 2;
906        tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
907                                                 ctxt->defMax *
908                                                 sizeof
909                                                 (xmlRelaxNGDefinePtr));
910        if (tmp == NULL) {
911            xmlRngPErrMemory(ctxt, "allocating define\n");
912            return (NULL);
913        }
914        ctxt->defTab = tmp;
915    }
916    ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
917    if (ret == NULL) {
918        xmlRngPErrMemory(ctxt, "allocating define\n");
919        return (NULL);
920    }
921    memset(ret, 0, sizeof(xmlRelaxNGDefine));
922    ctxt->defTab[ctxt->defNr++] = ret;
923    ret->node = node;
924    ret->depth = -1;
925    return (ret);
926}
927
928/**
929 * xmlRelaxNGFreePartition:
930 * @partitions:  a partition set structure
931 *
932 * Deallocate RelaxNG partition set structures.
933 */
934static void
935xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
936{
937    xmlRelaxNGInterleaveGroupPtr group;
938    int j;
939
940    if (partitions != NULL) {
941        if (partitions->groups != NULL) {
942            for (j = 0; j < partitions->nbgroups; j++) {
943                group = partitions->groups[j];
944                if (group != NULL) {
945                    if (group->defs != NULL)
946                        xmlFree(group->defs);
947                    if (group->attrs != NULL)
948                        xmlFree(group->attrs);
949                    xmlFree(group);
950                }
951            }
952            xmlFree(partitions->groups);
953        }
954        if (partitions->triage != NULL) {
955            xmlHashFree(partitions->triage, NULL);
956        }
957        xmlFree(partitions);
958    }
959}
960
961/**
962 * xmlRelaxNGFreeDefine:
963 * @define:  a define structure
964 *
965 * Deallocate a RelaxNG define structure.
966 */
967static void
968xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
969{
970    if (define == NULL)
971        return;
972
973    if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
974        xmlRelaxNGTypeLibraryPtr lib;
975
976        lib = (xmlRelaxNGTypeLibraryPtr) define->data;
977        if ((lib != NULL) && (lib->freef != NULL))
978            lib->freef(lib->data, (void *) define->attrs);
979    }
980    if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
981        xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
982    if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
983        xmlHashFree((xmlHashTablePtr) define->data, NULL);
984    if (define->name != NULL)
985        xmlFree(define->name);
986    if (define->ns != NULL)
987        xmlFree(define->ns);
988    if (define->value != NULL)
989        xmlFree(define->value);
990    if (define->contModel != NULL)
991        xmlRegFreeRegexp(define->contModel);
992    xmlFree(define);
993}
994
995/**
996 * xmlRelaxNGNewStates:
997 * @ctxt:  a Relax-NG validation context
998 * @size:  the default size for the container
999 *
1000 * Allocate a new RelaxNG validation state container
1001 *
1002 * Returns the newly allocated structure or NULL in case or error
1003 */
1004static xmlRelaxNGStatesPtr
1005xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
1006{
1007    xmlRelaxNGStatesPtr ret;
1008
1009    if ((ctxt != NULL) &&
1010        (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
1011        ctxt->freeStatesNr--;
1012        ret = ctxt->freeStates[ctxt->freeStatesNr];
1013        ret->nbState = 0;
1014        return (ret);
1015    }
1016    if (size < 16)
1017        size = 16;
1018
1019    ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
1020                                          (size -
1021                                           1) *
1022                                          sizeof(xmlRelaxNGValidStatePtr));
1023    if (ret == NULL) {
1024        xmlRngVErrMemory(ctxt, "allocating states\n");
1025        return (NULL);
1026    }
1027    ret->nbState = 0;
1028    ret->maxState = size;
1029    ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1030                                                          sizeof
1031                                                          (xmlRelaxNGValidStatePtr));
1032    if (ret->tabState == NULL) {
1033        xmlRngVErrMemory(ctxt, "allocating states\n");
1034        xmlFree(ret);
1035        return (NULL);
1036    }
1037    return (ret);
1038}
1039
1040/**
1041 * xmlRelaxNGAddStateUniq:
1042 * @ctxt:  a Relax-NG validation context
1043 * @states:  the states container
1044 * @state:  the validation state
1045 *
1046 * Add a RelaxNG validation state to the container without checking
1047 * for unicity.
1048 *
1049 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1050 */
1051static int
1052xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
1053                        xmlRelaxNGStatesPtr states,
1054                        xmlRelaxNGValidStatePtr state)
1055{
1056    if (state == NULL) {
1057        return (-1);
1058    }
1059    if (states->nbState >= states->maxState) {
1060        xmlRelaxNGValidStatePtr *tmp;
1061        int size;
1062
1063        size = states->maxState * 2;
1064        tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1065                                                     (size) *
1066                                                     sizeof
1067                                                     (xmlRelaxNGValidStatePtr));
1068        if (tmp == NULL) {
1069            xmlRngVErrMemory(ctxt, "adding states\n");
1070            return (-1);
1071        }
1072        states->tabState = tmp;
1073        states->maxState = size;
1074    }
1075    states->tabState[states->nbState++] = state;
1076    return (1);
1077}
1078
1079/**
1080 * xmlRelaxNGAddState:
1081 * @ctxt:  a Relax-NG validation context
1082 * @states:  the states container
1083 * @state:  the validation state
1084 *
1085 * Add a RelaxNG validation state to the container
1086 *
1087 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1088 */
1089static int
1090xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1091                    xmlRelaxNGStatesPtr states,
1092                    xmlRelaxNGValidStatePtr state)
1093{
1094    int i;
1095
1096    if (state == NULL) {
1097        return (-1);
1098    }
1099    if (states->nbState >= states->maxState) {
1100        xmlRelaxNGValidStatePtr *tmp;
1101        int size;
1102
1103        size = states->maxState * 2;
1104        tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1105                                                     (size) *
1106                                                     sizeof
1107                                                     (xmlRelaxNGValidStatePtr));
1108        if (tmp == NULL) {
1109            xmlRngVErrMemory(ctxt, "adding states\n");
1110            return (-1);
1111        }
1112        states->tabState = tmp;
1113        states->maxState = size;
1114    }
1115    for (i = 0; i < states->nbState; i++) {
1116        if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1117            xmlRelaxNGFreeValidState(ctxt, state);
1118            return (0);
1119        }
1120    }
1121    states->tabState[states->nbState++] = state;
1122    return (1);
1123}
1124
1125/**
1126 * xmlRelaxNGFreeStates:
1127 * @ctxt:  a Relax-NG validation context
1128 * @states:  teh container
1129 *
1130 * Free a RelaxNG validation state container
1131 */
1132static void
1133xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
1134                     xmlRelaxNGStatesPtr states)
1135{
1136    if (states == NULL)
1137        return;
1138    if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
1139        ctxt->freeStatesMax = 40;
1140        ctxt->freeStatesNr = 0;
1141        ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1142            xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1143        if (ctxt->freeStates == NULL) {
1144            xmlRngVErrMemory(ctxt, "storing states\n");
1145        }
1146    } else if ((ctxt != NULL)
1147               && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1148        xmlRelaxNGStatesPtr *tmp;
1149
1150        tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1151                                                 2 * ctxt->freeStatesMax *
1152                                                 sizeof
1153                                                 (xmlRelaxNGStatesPtr));
1154        if (tmp == NULL) {
1155            xmlRngVErrMemory(ctxt, "storing states\n");
1156            xmlFree(states->tabState);
1157            xmlFree(states);
1158            return;
1159        }
1160        ctxt->freeStates = tmp;
1161        ctxt->freeStatesMax *= 2;
1162    }
1163    if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
1164        xmlFree(states->tabState);
1165        xmlFree(states);
1166    } else {
1167        ctxt->freeStates[ctxt->freeStatesNr++] = states;
1168    }
1169}
1170
1171/**
1172 * xmlRelaxNGNewValidState:
1173 * @ctxt:  a Relax-NG validation context
1174 * @node:  the current node or NULL for the document
1175 *
1176 * Allocate a new RelaxNG validation state
1177 *
1178 * Returns the newly allocated structure or NULL in case or error
1179 */
1180static xmlRelaxNGValidStatePtr
1181xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1182{
1183    xmlRelaxNGValidStatePtr ret;
1184    xmlAttrPtr attr;
1185    xmlAttrPtr attrs[MAX_ATTR];
1186    int nbAttrs = 0;
1187    xmlNodePtr root = NULL;
1188
1189    if (node == NULL) {
1190        root = xmlDocGetRootElement(ctxt->doc);
1191        if (root == NULL)
1192            return (NULL);
1193    } else {
1194        attr = node->properties;
1195        while (attr != NULL) {
1196            if (nbAttrs < MAX_ATTR)
1197                attrs[nbAttrs++] = attr;
1198            else
1199                nbAttrs++;
1200            attr = attr->next;
1201        }
1202    }
1203    if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1204        ctxt->freeState->nbState--;
1205        ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1206    } else {
1207        ret =
1208            (xmlRelaxNGValidStatePtr)
1209            xmlMalloc(sizeof(xmlRelaxNGValidState));
1210        if (ret == NULL) {
1211            xmlRngVErrMemory(ctxt, "allocating states\n");
1212            return (NULL);
1213        }
1214        memset(ret, 0, sizeof(xmlRelaxNGValidState));
1215    }
1216    ret->value = NULL;
1217    ret->endvalue = NULL;
1218    if (node == NULL) {
1219        ret->node = (xmlNodePtr) ctxt->doc;
1220        ret->seq = root;
1221    } else {
1222        ret->node = node;
1223        ret->seq = node->children;
1224    }
1225    ret->nbAttrs = 0;
1226    if (nbAttrs > 0) {
1227        if (ret->attrs == NULL) {
1228            if (nbAttrs < 4)
1229                ret->maxAttrs = 4;
1230            else
1231                ret->maxAttrs = nbAttrs;
1232            ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1233                                                  sizeof(xmlAttrPtr));
1234            if (ret->attrs == NULL) {
1235                xmlRngVErrMemory(ctxt, "allocating states\n");
1236                return (ret);
1237            }
1238        } else if (ret->maxAttrs < nbAttrs) {
1239            xmlAttrPtr *tmp;
1240
1241            tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1242                                            sizeof(xmlAttrPtr));
1243            if (tmp == NULL) {
1244                xmlRngVErrMemory(ctxt, "allocating states\n");
1245                return (ret);
1246            }
1247            ret->attrs = tmp;
1248            ret->maxAttrs = nbAttrs;
1249        }
1250        ret->nbAttrs = nbAttrs;
1251        if (nbAttrs < MAX_ATTR) {
1252            memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1253        } else {
1254            attr = node->properties;
1255            nbAttrs = 0;
1256            while (attr != NULL) {
1257                ret->attrs[nbAttrs++] = attr;
1258                attr = attr->next;
1259            }
1260        }
1261    }
1262    ret->nbAttrLeft = ret->nbAttrs;
1263    return (ret);
1264}
1265
1266/**
1267 * xmlRelaxNGCopyValidState:
1268 * @ctxt:  a Relax-NG validation context
1269 * @state:  a validation state
1270 *
1271 * Copy the validation state
1272 *
1273 * Returns the newly allocated structure or NULL in case or error
1274 */
1275static xmlRelaxNGValidStatePtr
1276xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1277                         xmlRelaxNGValidStatePtr state)
1278{
1279    xmlRelaxNGValidStatePtr ret;
1280    unsigned int maxAttrs;
1281    xmlAttrPtr *attrs;
1282
1283    if (state == NULL)
1284        return (NULL);
1285    if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1286        ctxt->freeState->nbState--;
1287        ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1288    } else {
1289        ret =
1290            (xmlRelaxNGValidStatePtr)
1291            xmlMalloc(sizeof(xmlRelaxNGValidState));
1292        if (ret == NULL) {
1293            xmlRngVErrMemory(ctxt, "allocating states\n");
1294            return (NULL);
1295        }
1296        memset(ret, 0, sizeof(xmlRelaxNGValidState));
1297    }
1298    attrs = ret->attrs;
1299    maxAttrs = ret->maxAttrs;
1300    memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1301    ret->attrs = attrs;
1302    ret->maxAttrs = maxAttrs;
1303    if (state->nbAttrs > 0) {
1304        if (ret->attrs == NULL) {
1305            ret->maxAttrs = state->maxAttrs;
1306            ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1307                                                  sizeof(xmlAttrPtr));
1308            if (ret->attrs == NULL) {
1309                xmlRngVErrMemory(ctxt, "allocating states\n");
1310                ret->nbAttrs = 0;
1311                return (ret);
1312            }
1313        } else if (ret->maxAttrs < state->nbAttrs) {
1314            xmlAttrPtr *tmp;
1315
1316            tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1317                                            sizeof(xmlAttrPtr));
1318            if (tmp == NULL) {
1319                xmlRngVErrMemory(ctxt, "allocating states\n");
1320                ret->nbAttrs = 0;
1321                return (ret);
1322            }
1323            ret->maxAttrs = state->maxAttrs;
1324            ret->attrs = tmp;
1325        }
1326        memcpy(ret->attrs, state->attrs,
1327               state->nbAttrs * sizeof(xmlAttrPtr));
1328    }
1329    return (ret);
1330}
1331
1332/**
1333 * xmlRelaxNGEqualValidState:
1334 * @ctxt:  a Relax-NG validation context
1335 * @state1:  a validation state
1336 * @state2:  a validation state
1337 *
1338 * Compare the validation states for equality
1339 *
1340 * Returns 1 if equald, 0 otherwise
1341 */
1342static int
1343xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1344                          xmlRelaxNGValidStatePtr state1,
1345                          xmlRelaxNGValidStatePtr state2)
1346{
1347    int i;
1348
1349    if ((state1 == NULL) || (state2 == NULL))
1350        return (0);
1351    if (state1 == state2)
1352        return (1);
1353    if (state1->node != state2->node)
1354        return (0);
1355    if (state1->seq != state2->seq)
1356        return (0);
1357    if (state1->nbAttrLeft != state2->nbAttrLeft)
1358        return (0);
1359    if (state1->nbAttrs != state2->nbAttrs)
1360        return (0);
1361    if (state1->endvalue != state2->endvalue)
1362        return (0);
1363    if ((state1->value != state2->value) &&
1364        (!xmlStrEqual(state1->value, state2->value)))
1365        return (0);
1366    for (i = 0; i < state1->nbAttrs; i++) {
1367        if (state1->attrs[i] != state2->attrs[i])
1368            return (0);
1369    }
1370    return (1);
1371}
1372
1373/**
1374 * xmlRelaxNGFreeValidState:
1375 * @state:  a validation state structure
1376 *
1377 * Deallocate a RelaxNG validation state structure.
1378 */
1379static void
1380xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1381                         xmlRelaxNGValidStatePtr state)
1382{
1383    if (state == NULL)
1384        return;
1385
1386    if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1387        ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1388    }
1389    if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1390        if (state->attrs != NULL)
1391            xmlFree(state->attrs);
1392        xmlFree(state);
1393    } else {
1394        xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1395    }
1396}
1397
1398/************************************************************************
1399 * 									*
1400 * 			Semi internal functions				*
1401 * 									*
1402 ************************************************************************/
1403
1404/**
1405 * xmlRelaxParserSetFlag:
1406 * @ctxt: a RelaxNG parser context
1407 * @flags: a set of flags values
1408 *
1409 * Semi private function used to pass informations to a parser context
1410 * which are a combination of xmlRelaxNGParserFlag .
1411 *
1412 * Returns 0 if success and -1 in case of error
1413 */
1414int
1415xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1416{
1417    if (ctxt == NULL) return(-1);
1418    if (flags & XML_RELAXNGP_FREE_DOC) {
1419        ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1420	flags -= XML_RELAXNGP_FREE_DOC;
1421    }
1422    if (flags & XML_RELAXNGP_CRNG) {
1423        ctxt->crng |= XML_RELAXNGP_CRNG;
1424	flags -= XML_RELAXNGP_CRNG;
1425    }
1426    if (flags != 0) return(-1);
1427    return(0);
1428}
1429
1430/************************************************************************
1431 * 									*
1432 * 			Document functions				*
1433 * 									*
1434 ************************************************************************/
1435static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1436                                      xmlDocPtr doc);
1437
1438/**
1439 * xmlRelaxNGIncludePush:
1440 * @ctxt:  the parser context
1441 * @value:  the element doc
1442 *
1443 * Pushes a new include on top of the include stack
1444 *
1445 * Returns 0 in case of error, the index in the stack otherwise
1446 */
1447static int
1448xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1449                      xmlRelaxNGIncludePtr value)
1450{
1451    if (ctxt->incTab == NULL) {
1452        ctxt->incMax = 4;
1453        ctxt->incNr = 0;
1454        ctxt->incTab =
1455            (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1456                                               sizeof(ctxt->incTab[0]));
1457        if (ctxt->incTab == NULL) {
1458            xmlRngPErrMemory(ctxt, "allocating include\n");
1459            return (0);
1460        }
1461    }
1462    if (ctxt->incNr >= ctxt->incMax) {
1463        ctxt->incMax *= 2;
1464        ctxt->incTab =
1465            (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1466                                                ctxt->incMax *
1467                                                sizeof(ctxt->incTab[0]));
1468        if (ctxt->incTab == NULL) {
1469            xmlRngPErrMemory(ctxt, "allocating include\n");
1470            return (0);
1471        }
1472    }
1473    ctxt->incTab[ctxt->incNr] = value;
1474    ctxt->inc = value;
1475    return (ctxt->incNr++);
1476}
1477
1478/**
1479 * xmlRelaxNGIncludePop:
1480 * @ctxt: the parser context
1481 *
1482 * Pops the top include from the include stack
1483 *
1484 * Returns the include just removed
1485 */
1486static xmlRelaxNGIncludePtr
1487xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1488{
1489    xmlRelaxNGIncludePtr ret;
1490
1491    if (ctxt->incNr <= 0)
1492        return (NULL);
1493    ctxt->incNr--;
1494    if (ctxt->incNr > 0)
1495        ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1496    else
1497        ctxt->inc = NULL;
1498    ret = ctxt->incTab[ctxt->incNr];
1499    ctxt->incTab[ctxt->incNr] = NULL;
1500    return (ret);
1501}
1502
1503/**
1504 * xmlRelaxNGRemoveRedefine:
1505 * @ctxt: the parser context
1506 * @URL:  the normalized URL
1507 * @target:  the included target
1508 * @name:  the define name to eliminate
1509 *
1510 * Applies the elimination algorithm of 4.7
1511 *
1512 * Returns 0 in case of error, 1 in case of success.
1513 */
1514static int
1515xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1516                         const xmlChar * URL ATTRIBUTE_UNUSED,
1517                         xmlNodePtr target, const xmlChar * name)
1518{
1519    int found = 0;
1520    xmlNodePtr tmp, tmp2;
1521    xmlChar *name2;
1522
1523#ifdef DEBUG_INCLUDE
1524    if (name == NULL)
1525        xmlGenericError(xmlGenericErrorContext,
1526                        "Elimination of <include> start from %s\n", URL);
1527    else
1528        xmlGenericError(xmlGenericErrorContext,
1529                        "Elimination of <include> define %s from %s\n",
1530                        name, URL);
1531#endif
1532    tmp = target;
1533    while (tmp != NULL) {
1534        tmp2 = tmp->next;
1535        if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1536            found = 1;
1537            xmlUnlinkNode(tmp);
1538            xmlFreeNode(tmp);
1539        } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1540            name2 = xmlGetProp(tmp, BAD_CAST "name");
1541            xmlRelaxNGNormExtSpace(name2);
1542            if (name2 != NULL) {
1543                if (xmlStrEqual(name, name2)) {
1544                    found = 1;
1545                    xmlUnlinkNode(tmp);
1546                    xmlFreeNode(tmp);
1547                }
1548                xmlFree(name2);
1549            }
1550        } else if (IS_RELAXNG(tmp, "include")) {
1551            xmlChar *href = NULL;
1552            xmlRelaxNGDocumentPtr inc = tmp->psvi;
1553
1554            if ((inc != NULL) && (inc->doc != NULL) &&
1555                (inc->doc->children != NULL)) {
1556
1557                if (xmlStrEqual
1558                    (inc->doc->children->name, BAD_CAST "grammar")) {
1559#ifdef DEBUG_INCLUDE
1560                    href = xmlGetProp(tmp, BAD_CAST "href");
1561#endif
1562                    if (xmlRelaxNGRemoveRedefine(ctxt, href,
1563                                                 inc->doc->children->
1564                                                 children, name) == 1) {
1565                        found = 1;
1566                    }
1567#ifdef DEBUG_INCLUDE
1568                    if (href != NULL)
1569                        xmlFree(href);
1570#endif
1571                }
1572            }
1573        }
1574        tmp = tmp2;
1575    }
1576    return (found);
1577}
1578
1579/**
1580 * xmlRelaxNGLoadInclude:
1581 * @ctxt: the parser context
1582 * @URL:  the normalized URL
1583 * @node: the include node.
1584 * @ns:  the namespace passed from the context.
1585 *
1586 * First lookup if the document is already loaded into the parser context,
1587 * check against recursion. If not found the resource is loaded and
1588 * the content is preprocessed before being returned back to the caller.
1589 *
1590 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1591 */
1592static xmlRelaxNGIncludePtr
1593xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1594                      xmlNodePtr node, const xmlChar * ns)
1595{
1596    xmlRelaxNGIncludePtr ret = NULL;
1597    xmlDocPtr doc;
1598    int i;
1599    xmlNodePtr root, cur;
1600
1601#ifdef DEBUG_INCLUDE
1602    xmlGenericError(xmlGenericErrorContext,
1603                    "xmlRelaxNGLoadInclude(%s)\n", URL);
1604#endif
1605
1606    /*
1607     * check against recursion in the stack
1608     */
1609    for (i = 0; i < ctxt->incNr; i++) {
1610        if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1611            xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1612                       "Detected an Include recursion for %s\n", URL,
1613                       NULL);
1614            return (NULL);
1615        }
1616    }
1617
1618    /*
1619     * load the document
1620     */
1621    doc = xmlReadFile((const char *) URL,NULL,0);
1622    if (doc == NULL) {
1623        xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1624                   "xmlRelaxNG: could not load %s\n", URL, NULL);
1625        return (NULL);
1626    }
1627#ifdef DEBUG_INCLUDE
1628    xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
1629#endif
1630
1631    /*
1632     * Allocate the document structures and register it first.
1633     */
1634    ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1635    if (ret == NULL) {
1636        xmlRngPErrMemory(ctxt, "allocating include\n");
1637        xmlFreeDoc(doc);
1638        return (NULL);
1639    }
1640    memset(ret, 0, sizeof(xmlRelaxNGInclude));
1641    ret->doc = doc;
1642    ret->href = xmlStrdup(URL);
1643    ret->next = ctxt->includes;
1644    ctxt->includes = ret;
1645
1646    /*
1647     * transmit the ns if needed
1648     */
1649    if (ns != NULL) {
1650        root = xmlDocGetRootElement(doc);
1651        if (root != NULL) {
1652            if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1653                xmlSetProp(root, BAD_CAST "ns", ns);
1654            }
1655        }
1656    }
1657
1658    /*
1659     * push it on the stack
1660     */
1661    xmlRelaxNGIncludePush(ctxt, ret);
1662
1663    /*
1664     * Some preprocessing of the document content, this include recursing
1665     * in the include stack.
1666     */
1667#ifdef DEBUG_INCLUDE
1668    xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
1669#endif
1670
1671    doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1672    if (doc == NULL) {
1673        ctxt->inc = NULL;
1674        return (NULL);
1675    }
1676
1677    /*
1678     * Pop up the include from the stack
1679     */
1680    xmlRelaxNGIncludePop(ctxt);
1681
1682#ifdef DEBUG_INCLUDE
1683    xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
1684#endif
1685    /*
1686     * Check that the top element is a grammar
1687     */
1688    root = xmlDocGetRootElement(doc);
1689    if (root == NULL) {
1690        xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1691                   "xmlRelaxNG: included document is empty %s\n", URL,
1692                   NULL);
1693        return (NULL);
1694    }
1695    if (!IS_RELAXNG(root, "grammar")) {
1696        xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1697                   "xmlRelaxNG: included document %s root is not a grammar\n",
1698                   URL, NULL);
1699        return (NULL);
1700    }
1701
1702    /*
1703     * Elimination of redefined rules in the include.
1704     */
1705    cur = node->children;
1706    while (cur != NULL) {
1707        if (IS_RELAXNG(cur, "start")) {
1708            int found = 0;
1709
1710            found =
1711                xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1712            if (!found) {
1713                xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1714                           "xmlRelaxNG: include %s has a start but not the included grammar\n",
1715                           URL, NULL);
1716            }
1717        } else if (IS_RELAXNG(cur, "define")) {
1718            xmlChar *name;
1719
1720            name = xmlGetProp(cur, BAD_CAST "name");
1721            if (name == NULL) {
1722                xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1723                           "xmlRelaxNG: include %s has define without name\n",
1724                           URL, NULL);
1725            } else {
1726                int found;
1727
1728                xmlRelaxNGNormExtSpace(name);
1729                found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1730                                                 root->children, name);
1731                if (!found) {
1732                    xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1733                               "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1734                               URL, name);
1735                }
1736                xmlFree(name);
1737            }
1738        }
1739        cur = cur->next;
1740    }
1741
1742
1743    return (ret);
1744}
1745
1746/**
1747 * xmlRelaxNGValidErrorPush:
1748 * @ctxt:  the validation context
1749 * @err:  the error code
1750 * @arg1:  the first string argument
1751 * @arg2:  the second string argument
1752 * @dup:  arg need to be duplicated
1753 *
1754 * Pushes a new error on top of the error stack
1755 *
1756 * Returns 0 in case of error, the index in the stack otherwise
1757 */
1758static int
1759xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1760                         xmlRelaxNGValidErr err, const xmlChar * arg1,
1761                         const xmlChar * arg2, int dup)
1762{
1763    xmlRelaxNGValidErrorPtr cur;
1764
1765#ifdef DEBUG_ERROR
1766    xmlGenericError(xmlGenericErrorContext,
1767                    "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1768#endif
1769    if (ctxt->errTab == NULL) {
1770        ctxt->errMax = 8;
1771        ctxt->errNr = 0;
1772        ctxt->errTab =
1773            (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1774                                                sizeof
1775                                                (xmlRelaxNGValidError));
1776        if (ctxt->errTab == NULL) {
1777            xmlRngVErrMemory(ctxt, "pushing error\n");
1778            return (0);
1779        }
1780        ctxt->err = NULL;
1781    }
1782    if (ctxt->errNr >= ctxt->errMax) {
1783        ctxt->errMax *= 2;
1784        ctxt->errTab =
1785            (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1786                                                 ctxt->errMax *
1787                                                 sizeof
1788                                                 (xmlRelaxNGValidError));
1789        if (ctxt->errTab == NULL) {
1790            xmlRngVErrMemory(ctxt, "pushing error\n");
1791            return (0);
1792        }
1793        ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1794    }
1795    if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
1796        (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1797        return (ctxt->errNr);
1798    cur = &ctxt->errTab[ctxt->errNr];
1799    cur->err = err;
1800    if (dup) {
1801        cur->arg1 = xmlStrdup(arg1);
1802        cur->arg2 = xmlStrdup(arg2);
1803        cur->flags = ERROR_IS_DUP;
1804    } else {
1805        cur->arg1 = arg1;
1806        cur->arg2 = arg2;
1807        cur->flags = 0;
1808    }
1809    if (ctxt->state != NULL) {
1810        cur->node = ctxt->state->node;
1811        cur->seq = ctxt->state->seq;
1812    } else {
1813        cur->node = NULL;
1814        cur->seq = NULL;
1815    }
1816    ctxt->err = cur;
1817    return (ctxt->errNr++);
1818}
1819
1820/**
1821 * xmlRelaxNGValidErrorPop:
1822 * @ctxt: the validation context
1823 *
1824 * Pops the top error from the error stack
1825 */
1826static void
1827xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1828{
1829    xmlRelaxNGValidErrorPtr cur;
1830
1831    if (ctxt->errNr <= 0) {
1832        ctxt->err = NULL;
1833        return;
1834    }
1835    ctxt->errNr--;
1836    if (ctxt->errNr > 0)
1837        ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1838    else
1839        ctxt->err = NULL;
1840    cur = &ctxt->errTab[ctxt->errNr];
1841    if (cur->flags & ERROR_IS_DUP) {
1842        if (cur->arg1 != NULL)
1843            xmlFree((xmlChar *) cur->arg1);
1844        cur->arg1 = NULL;
1845        if (cur->arg2 != NULL)
1846            xmlFree((xmlChar *) cur->arg2);
1847        cur->arg2 = NULL;
1848        cur->flags = 0;
1849    }
1850}
1851
1852/**
1853 * xmlRelaxNGDocumentPush:
1854 * @ctxt:  the parser context
1855 * @value:  the element doc
1856 *
1857 * Pushes a new doc on top of the doc stack
1858 *
1859 * Returns 0 in case of error, the index in the stack otherwise
1860 */
1861static int
1862xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1863                       xmlRelaxNGDocumentPtr value)
1864{
1865    if (ctxt->docTab == NULL) {
1866        ctxt->docMax = 4;
1867        ctxt->docNr = 0;
1868        ctxt->docTab =
1869            (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1870                                                sizeof(ctxt->docTab[0]));
1871        if (ctxt->docTab == NULL) {
1872            xmlRngPErrMemory(ctxt, "adding document\n");
1873            return (0);
1874        }
1875    }
1876    if (ctxt->docNr >= ctxt->docMax) {
1877        ctxt->docMax *= 2;
1878        ctxt->docTab =
1879            (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1880                                                 ctxt->docMax *
1881                                                 sizeof(ctxt->docTab[0]));
1882        if (ctxt->docTab == NULL) {
1883            xmlRngPErrMemory(ctxt, "adding document\n");
1884            return (0);
1885        }
1886    }
1887    ctxt->docTab[ctxt->docNr] = value;
1888    ctxt->doc = value;
1889    return (ctxt->docNr++);
1890}
1891
1892/**
1893 * xmlRelaxNGDocumentPop:
1894 * @ctxt: the parser context
1895 *
1896 * Pops the top doc from the doc stack
1897 *
1898 * Returns the doc just removed
1899 */
1900static xmlRelaxNGDocumentPtr
1901xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1902{
1903    xmlRelaxNGDocumentPtr ret;
1904
1905    if (ctxt->docNr <= 0)
1906        return (NULL);
1907    ctxt->docNr--;
1908    if (ctxt->docNr > 0)
1909        ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1910    else
1911        ctxt->doc = NULL;
1912    ret = ctxt->docTab[ctxt->docNr];
1913    ctxt->docTab[ctxt->docNr] = NULL;
1914    return (ret);
1915}
1916
1917/**
1918 * xmlRelaxNGLoadExternalRef:
1919 * @ctxt: the parser context
1920 * @URL:  the normalized URL
1921 * @ns:  the inherited ns if any
1922 *
1923 * First lookup if the document is already loaded into the parser context,
1924 * check against recursion. If not found the resource is loaded and
1925 * the content is preprocessed before being returned back to the caller.
1926 *
1927 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1928 */
1929static xmlRelaxNGDocumentPtr
1930xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1931                          const xmlChar * URL, const xmlChar * ns)
1932{
1933    xmlRelaxNGDocumentPtr ret = NULL;
1934    xmlDocPtr doc;
1935    xmlNodePtr root;
1936    int i;
1937
1938    /*
1939     * check against recursion in the stack
1940     */
1941    for (i = 0; i < ctxt->docNr; i++) {
1942        if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1943            xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1944                       "Detected an externalRef recursion for %s\n", URL,
1945                       NULL);
1946            return (NULL);
1947        }
1948    }
1949
1950    /*
1951     * load the document
1952     */
1953    doc = xmlReadFile((const char *) URL,NULL,0);
1954    if (doc == NULL) {
1955        xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1956                   "xmlRelaxNG: could not load %s\n", URL, NULL);
1957        return (NULL);
1958    }
1959
1960    /*
1961     * Allocate the document structures and register it first.
1962     */
1963    ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1964    if (ret == NULL) {
1965        xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1966                   "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1967        xmlFreeDoc(doc);
1968        return (NULL);
1969    }
1970    memset(ret, 0, sizeof(xmlRelaxNGDocument));
1971    ret->doc = doc;
1972    ret->href = xmlStrdup(URL);
1973    ret->next = ctxt->documents;
1974    ret->externalRef = 1;
1975    ctxt->documents = ret;
1976
1977    /*
1978     * transmit the ns if needed
1979     */
1980    if (ns != NULL) {
1981        root = xmlDocGetRootElement(doc);
1982        if (root != NULL) {
1983            if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1984                xmlSetProp(root, BAD_CAST "ns", ns);
1985            }
1986        }
1987    }
1988
1989    /*
1990     * push it on the stack and register it in the hash table
1991     */
1992    xmlRelaxNGDocumentPush(ctxt, ret);
1993
1994    /*
1995     * Some preprocessing of the document content
1996     */
1997    doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1998    if (doc == NULL) {
1999        ctxt->doc = NULL;
2000        return (NULL);
2001    }
2002
2003    xmlRelaxNGDocumentPop(ctxt);
2004
2005    return (ret);
2006}
2007
2008/************************************************************************
2009 * 									*
2010 * 			Error functions					*
2011 * 									*
2012 ************************************************************************/
2013
2014#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2015#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2016#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2017#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2018#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2019
2020static const char *
2021xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2022{
2023    if (def == NULL)
2024        return ("none");
2025    switch (def->type) {
2026        case XML_RELAXNG_EMPTY:
2027            return ("empty");
2028        case XML_RELAXNG_NOT_ALLOWED:
2029            return ("notAllowed");
2030        case XML_RELAXNG_EXCEPT:
2031            return ("except");
2032        case XML_RELAXNG_TEXT:
2033            return ("text");
2034        case XML_RELAXNG_ELEMENT:
2035            return ("element");
2036        case XML_RELAXNG_DATATYPE:
2037            return ("datatype");
2038        case XML_RELAXNG_VALUE:
2039            return ("value");
2040        case XML_RELAXNG_LIST:
2041            return ("list");
2042        case XML_RELAXNG_ATTRIBUTE:
2043            return ("attribute");
2044        case XML_RELAXNG_DEF:
2045            return ("def");
2046        case XML_RELAXNG_REF:
2047            return ("ref");
2048        case XML_RELAXNG_EXTERNALREF:
2049            return ("externalRef");
2050        case XML_RELAXNG_PARENTREF:
2051            return ("parentRef");
2052        case XML_RELAXNG_OPTIONAL:
2053            return ("optional");
2054        case XML_RELAXNG_ZEROORMORE:
2055            return ("zeroOrMore");
2056        case XML_RELAXNG_ONEORMORE:
2057            return ("oneOrMore");
2058        case XML_RELAXNG_CHOICE:
2059            return ("choice");
2060        case XML_RELAXNG_GROUP:
2061            return ("group");
2062        case XML_RELAXNG_INTERLEAVE:
2063            return ("interleave");
2064        case XML_RELAXNG_START:
2065            return ("start");
2066        case XML_RELAXNG_NOOP:
2067            return ("noop");
2068        case XML_RELAXNG_PARAM:
2069            return ("param");
2070    }
2071    return ("unknown");
2072}
2073
2074/**
2075 * xmlRelaxNGGetErrorString:
2076 * @err:  the error code
2077 * @arg1:  the first string argument
2078 * @arg2:  the second string argument
2079 *
2080 * computes a formatted error string for the given error code and args
2081 *
2082 * Returns the error string, it must be deallocated by the caller
2083 */
2084static xmlChar *
2085xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2086                         const xmlChar * arg2)
2087{
2088    char msg[1000];
2089
2090    if (arg1 == NULL)
2091        arg1 = BAD_CAST "";
2092    if (arg2 == NULL)
2093        arg2 = BAD_CAST "";
2094
2095    msg[0] = 0;
2096    switch (err) {
2097        case XML_RELAXNG_OK:
2098            return (NULL);
2099        case XML_RELAXNG_ERR_MEMORY:
2100            return (xmlCharStrdup("out of memory\n"));
2101        case XML_RELAXNG_ERR_TYPE:
2102            snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2103            break;
2104        case XML_RELAXNG_ERR_TYPEVAL:
2105            snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2106                     arg2);
2107            break;
2108        case XML_RELAXNG_ERR_DUPID:
2109            snprintf(msg, 1000, "ID %s redefined\n", arg1);
2110            break;
2111        case XML_RELAXNG_ERR_TYPECMP:
2112            snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2113            break;
2114        case XML_RELAXNG_ERR_NOSTATE:
2115            return (xmlCharStrdup("Internal error: no state\n"));
2116        case XML_RELAXNG_ERR_NODEFINE:
2117            return (xmlCharStrdup("Internal error: no define\n"));
2118        case XML_RELAXNG_ERR_INTERNAL:
2119            snprintf(msg, 1000, "Internal error: %s\n", arg1);
2120            break;
2121        case XML_RELAXNG_ERR_LISTEXTRA:
2122            snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2123            break;
2124        case XML_RELAXNG_ERR_INTERNODATA:
2125            return (xmlCharStrdup
2126                    ("Internal: interleave block has no data\n"));
2127        case XML_RELAXNG_ERR_INTERSEQ:
2128            return (xmlCharStrdup("Invalid sequence in interleave\n"));
2129        case XML_RELAXNG_ERR_INTEREXTRA:
2130            snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2131            break;
2132        case XML_RELAXNG_ERR_ELEMNAME:
2133            snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2134                     arg2);
2135            break;
2136        case XML_RELAXNG_ERR_ELEMNONS:
2137            snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2138                     arg1);
2139            break;
2140        case XML_RELAXNG_ERR_ELEMWRONGNS:
2141            snprintf(msg, 1000,
2142                     "Element %s has wrong namespace: expecting %s\n", arg1,
2143                     arg2);
2144            break;
2145        case XML_RELAXNG_ERR_ELEMWRONG:
2146            snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2147            break;
2148        case XML_RELAXNG_ERR_TEXTWRONG:
2149            snprintf(msg, 1000,
2150                     "Did not expect text in element %s content\n", arg1);
2151            break;
2152        case XML_RELAXNG_ERR_ELEMEXTRANS:
2153            snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2154                     arg1);
2155            break;
2156        case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2157            snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2158            break;
2159        case XML_RELAXNG_ERR_NOELEM:
2160            snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2161                     arg1);
2162            break;
2163        case XML_RELAXNG_ERR_NOTELEM:
2164            return (xmlCharStrdup("Expecting an element got text\n"));
2165        case XML_RELAXNG_ERR_ATTRVALID:
2166            snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2167                     arg1);
2168            break;
2169        case XML_RELAXNG_ERR_CONTENTVALID:
2170            snprintf(msg, 1000, "Element %s failed to validate content\n",
2171                     arg1);
2172            break;
2173        case XML_RELAXNG_ERR_EXTRACONTENT:
2174            snprintf(msg, 1000, "Element %s has extra content: %s\n",
2175                     arg1, arg2);
2176            break;
2177        case XML_RELAXNG_ERR_INVALIDATTR:
2178            snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2179                     arg1, arg2);
2180            break;
2181        case XML_RELAXNG_ERR_LACKDATA:
2182            snprintf(msg, 1000, "Datatype element %s contains no data\n",
2183                     arg1);
2184            break;
2185        case XML_RELAXNG_ERR_DATAELEM:
2186            snprintf(msg, 1000, "Datatype element %s has child elements\n",
2187                     arg1);
2188            break;
2189        case XML_RELAXNG_ERR_VALELEM:
2190            snprintf(msg, 1000, "Value element %s has child elements\n",
2191                     arg1);
2192            break;
2193        case XML_RELAXNG_ERR_LISTELEM:
2194            snprintf(msg, 1000, "List element %s has child elements\n",
2195                     arg1);
2196            break;
2197        case XML_RELAXNG_ERR_DATATYPE:
2198            snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2199            break;
2200        case XML_RELAXNG_ERR_VALUE:
2201            snprintf(msg, 1000, "Error validating value %s\n", arg1);
2202            break;
2203        case XML_RELAXNG_ERR_LIST:
2204            return (xmlCharStrdup("Error validating list\n"));
2205        case XML_RELAXNG_ERR_NOGRAMMAR:
2206            return (xmlCharStrdup("No top grammar defined\n"));
2207        case XML_RELAXNG_ERR_EXTRADATA:
2208            return (xmlCharStrdup("Extra data in the document\n"));
2209        default:
2210            return (xmlCharStrdup("Unknown error !\n"));
2211    }
2212    if (msg[0] == 0) {
2213        snprintf(msg, 1000, "Unknown error code %d\n", err);
2214    }
2215    msg[1000 - 1] = 0;
2216    return (xmlStrdup((xmlChar *) msg));
2217}
2218
2219/**
2220 * xmlRelaxNGShowValidError:
2221 * @ctxt:  the validation context
2222 * @err:  the error number
2223 * @node:  the node
2224 * @child:  the node child generating the problem.
2225 * @arg1:  the first argument
2226 * @arg2:  the second argument
2227 *
2228 * Show a validation error.
2229 */
2230static void
2231xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2232                         xmlRelaxNGValidErr err, xmlNodePtr node,
2233                         xmlNodePtr child, const xmlChar * arg1,
2234                         const xmlChar * arg2)
2235{
2236    xmlChar *msg;
2237
2238    if (ctxt->flags & FLAGS_NOERROR)
2239        return;
2240
2241#ifdef DEBUG_ERROR
2242    xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
2243#endif
2244    msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2245    if (msg == NULL)
2246        return;
2247
2248    if (ctxt->errNo == XML_RELAXNG_OK)
2249        ctxt->errNo = err;
2250    xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2251               (const char *) msg, arg1, arg2);
2252    xmlFree(msg);
2253}
2254
2255/**
2256 * xmlRelaxNGPopErrors:
2257 * @ctxt:  the validation context
2258 * @level:  the error level in the stack
2259 *
2260 * pop and discard all errors until the given level is reached
2261 */
2262static void
2263xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2264{
2265    int i;
2266    xmlRelaxNGValidErrorPtr err;
2267
2268#ifdef DEBUG_ERROR
2269    xmlGenericError(xmlGenericErrorContext,
2270                    "Pop errors till level %d\n", level);
2271#endif
2272    for (i = level; i < ctxt->errNr; i++) {
2273        err = &ctxt->errTab[i];
2274        if (err->flags & ERROR_IS_DUP) {
2275            if (err->arg1 != NULL)
2276                xmlFree((xmlChar *) err->arg1);
2277            err->arg1 = NULL;
2278            if (err->arg2 != NULL)
2279                xmlFree((xmlChar *) err->arg2);
2280            err->arg2 = NULL;
2281            err->flags = 0;
2282        }
2283    }
2284    ctxt->errNr = level;
2285    if (ctxt->errNr <= 0)
2286        ctxt->err = NULL;
2287}
2288
2289/**
2290 * xmlRelaxNGDumpValidError:
2291 * @ctxt:  the validation context
2292 *
2293 * Show all validation error over a given index.
2294 */
2295static void
2296xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2297{
2298    int i, j, k;
2299    xmlRelaxNGValidErrorPtr err, dup;
2300
2301#ifdef DEBUG_ERROR
2302    xmlGenericError(xmlGenericErrorContext,
2303                    "Dumping error stack %d errors\n", ctxt->errNr);
2304#endif
2305    for (i = 0, k = 0; i < ctxt->errNr; i++) {
2306        err = &ctxt->errTab[i];
2307        if (k < MAX_ERROR) {
2308            for (j = 0; j < i; j++) {
2309                dup = &ctxt->errTab[j];
2310                if ((err->err == dup->err) && (err->node == dup->node) &&
2311                    (xmlStrEqual(err->arg1, dup->arg1)) &&
2312                    (xmlStrEqual(err->arg2, dup->arg2))) {
2313                    goto skip;
2314                }
2315            }
2316            xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2317                                     err->arg1, err->arg2);
2318            k++;
2319        }
2320      skip:
2321        if (err->flags & ERROR_IS_DUP) {
2322            if (err->arg1 != NULL)
2323                xmlFree((xmlChar *) err->arg1);
2324            err->arg1 = NULL;
2325            if (err->arg2 != NULL)
2326                xmlFree((xmlChar *) err->arg2);
2327            err->arg2 = NULL;
2328            err->flags = 0;
2329        }
2330    }
2331    ctxt->errNr = 0;
2332}
2333
2334/**
2335 * xmlRelaxNGAddValidError:
2336 * @ctxt:  the validation context
2337 * @err:  the error number
2338 * @arg1:  the first argument
2339 * @arg2:  the second argument
2340 * @dup:  need to dup the args
2341 *
2342 * Register a validation error, either generating it if it's sure
2343 * or stacking it for later handling if unsure.
2344 */
2345static void
2346xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2347                        xmlRelaxNGValidErr err, const xmlChar * arg1,
2348                        const xmlChar * arg2, int dup)
2349{
2350    if (ctxt == NULL)
2351        return;
2352    if (ctxt->flags & FLAGS_NOERROR)
2353        return;
2354
2355#ifdef DEBUG_ERROR
2356    xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
2357#endif
2358    /*
2359     * generate the error directly
2360     */
2361    if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2362    	 (ctxt->flags & FLAGS_NEGATIVE)) {
2363        xmlNodePtr node, seq;
2364
2365        /*
2366         * Flush first any stacked error which might be the
2367         * real cause of the problem.
2368         */
2369        if (ctxt->errNr != 0)
2370            xmlRelaxNGDumpValidError(ctxt);
2371        if (ctxt->state != NULL) {
2372            node = ctxt->state->node;
2373            seq = ctxt->state->seq;
2374        } else {
2375            node = seq = NULL;
2376        }
2377        xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2378    }
2379    /*
2380     * Stack the error for later processing if needed
2381     */
2382    else {
2383        xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
2384    }
2385}
2386
2387
2388/************************************************************************
2389 * 									*
2390 * 			Type library hooks				*
2391 * 									*
2392 ************************************************************************/
2393static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2394                                    const xmlChar * str);
2395
2396/**
2397 * xmlRelaxNGSchemaTypeHave:
2398 * @data:  data needed for the library
2399 * @type:  the type name
2400 *
2401 * Check if the given type is provided by
2402 * the W3C XMLSchema Datatype library.
2403 *
2404 * Returns 1 if yes, 0 if no and -1 in case of error.
2405 */
2406static int
2407xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2408{
2409    xmlSchemaTypePtr typ;
2410
2411    if (type == NULL)
2412        return (-1);
2413    typ = xmlSchemaGetPredefinedType(type,
2414                                     BAD_CAST
2415                                     "http://www.w3.org/2001/XMLSchema");
2416    if (typ == NULL)
2417        return (0);
2418    return (1);
2419}
2420
2421/**
2422 * xmlRelaxNGSchemaTypeCheck:
2423 * @data:  data needed for the library
2424 * @type:  the type name
2425 * @value:  the value to check
2426 * @node:  the node
2427 *
2428 * Check if the given type and value are validated by
2429 * the W3C XMLSchema Datatype library.
2430 *
2431 * Returns 1 if yes, 0 if no and -1 in case of error.
2432 */
2433static int
2434xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
2435                          const xmlChar * type,
2436                          const xmlChar * value,
2437                          void **result, xmlNodePtr node)
2438{
2439    xmlSchemaTypePtr typ;
2440    int ret;
2441
2442    if ((type == NULL) || (value == NULL))
2443        return (-1);
2444    typ = xmlSchemaGetPredefinedType(type,
2445                                     BAD_CAST
2446                                     "http://www.w3.org/2001/XMLSchema");
2447    if (typ == NULL)
2448        return (-1);
2449    ret = xmlSchemaValPredefTypeNode(typ, value,
2450                                     (xmlSchemaValPtr *) result, node);
2451    if (ret == 2)               /* special ID error code */
2452        return (2);
2453    if (ret == 0)
2454        return (1);
2455    if (ret > 0)
2456        return (0);
2457    return (-1);
2458}
2459
2460/**
2461 * xmlRelaxNGSchemaFacetCheck:
2462 * @data:  data needed for the library
2463 * @type:  the type name
2464 * @facet:  the facet name
2465 * @val:  the facet value
2466 * @strval:  the string value
2467 * @value:  the value to check
2468 *
2469 * Function provided by a type library to check a value facet
2470 *
2471 * Returns 1 if yes, 0 if no and -1 in case of error.
2472 */
2473static int
2474xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2475                           const xmlChar * type, const xmlChar * facetname,
2476                           const xmlChar * val, const xmlChar * strval,
2477                           void *value)
2478{
2479    xmlSchemaFacetPtr facet;
2480    xmlSchemaTypePtr typ;
2481    int ret;
2482
2483    if ((type == NULL) || (strval == NULL))
2484        return (-1);
2485    typ = xmlSchemaGetPredefinedType(type,
2486                                     BAD_CAST
2487                                     "http://www.w3.org/2001/XMLSchema");
2488    if (typ == NULL)
2489        return (-1);
2490
2491    facet = xmlSchemaNewFacet();
2492    if (facet == NULL)
2493        return (-1);
2494
2495    if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2496        facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2497    } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2498        facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2499    } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2500        facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2501    } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2502        facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2503    } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2504        facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2505    } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2506        facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2507    } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2508        facet->type = XML_SCHEMA_FACET_PATTERN;
2509    } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2510        facet->type = XML_SCHEMA_FACET_ENUMERATION;
2511    } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2512        facet->type = XML_SCHEMA_FACET_WHITESPACE;
2513    } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2514        facet->type = XML_SCHEMA_FACET_LENGTH;
2515    } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2516        facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2517    } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2518        facet->type = XML_SCHEMA_FACET_MINLENGTH;
2519    } else {
2520        xmlSchemaFreeFacet(facet);
2521        return (-1);
2522    }
2523    facet->value = val;
2524    ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2525    if (ret != 0) {
2526        xmlSchemaFreeFacet(facet);
2527        return (-1);
2528    }
2529    ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2530    xmlSchemaFreeFacet(facet);
2531    if (ret != 0)
2532        return (-1);
2533    return (0);
2534}
2535
2536/**
2537 * xmlRelaxNGSchemaFreeValue:
2538 * @data:  data needed for the library
2539 * @value:  the value to free
2540 *
2541 * Function provided by a type library to free a Schemas value
2542 *
2543 * Returns 1 if yes, 0 if no and -1 in case of error.
2544 */
2545static void
2546xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2547{
2548    xmlSchemaFreeValue(value);
2549}
2550
2551/**
2552 * xmlRelaxNGSchemaTypeCompare:
2553 * @data:  data needed for the library
2554 * @type:  the type name
2555 * @value1:  the first value
2556 * @value2:  the second value
2557 *
2558 * Compare two values for equality accordingly a type from the W3C XMLSchema
2559 * Datatype library.
2560 *
2561 * Returns 1 if equal, 0 if no and -1 in case of error.
2562 */
2563static int
2564xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2565                            const xmlChar * type,
2566                            const xmlChar * value1,
2567                            xmlNodePtr ctxt1,
2568                            void *comp1,
2569                            const xmlChar * value2, xmlNodePtr ctxt2)
2570{
2571    int ret;
2572    xmlSchemaTypePtr typ;
2573    xmlSchemaValPtr res1 = NULL, res2 = NULL;
2574
2575    if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2576        return (-1);
2577    typ = xmlSchemaGetPredefinedType(type,
2578                                     BAD_CAST
2579                                     "http://www.w3.org/2001/XMLSchema");
2580    if (typ == NULL)
2581        return (-1);
2582    if (comp1 == NULL) {
2583        ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2584        if (ret != 0)
2585            return (-1);
2586        if (res1 == NULL)
2587            return (-1);
2588    } else {
2589        res1 = (xmlSchemaValPtr) comp1;
2590    }
2591    ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
2592    if (ret != 0) {
2593	if ((comp1 == NULL) && (res1 != NULL))
2594	    xmlSchemaFreeValue(res1);
2595        return (-1);
2596    }
2597    if (res1 == NULL) {
2598        return (-1);
2599    }
2600    ret = xmlSchemaCompareValues(res1, res2);
2601    if (res1 != (xmlSchemaValPtr) comp1)
2602        xmlSchemaFreeValue(res1);
2603    xmlSchemaFreeValue(res2);
2604    if (ret == -2)
2605        return (-1);
2606    if (ret == 0)
2607        return (1);
2608    return (0);
2609}
2610
2611/**
2612 * xmlRelaxNGDefaultTypeHave:
2613 * @data:  data needed for the library
2614 * @type:  the type name
2615 *
2616 * Check if the given type is provided by
2617 * the default datatype library.
2618 *
2619 * Returns 1 if yes, 0 if no and -1 in case of error.
2620 */
2621static int
2622xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2623                          const xmlChar * type)
2624{
2625    if (type == NULL)
2626        return (-1);
2627    if (xmlStrEqual(type, BAD_CAST "string"))
2628        return (1);
2629    if (xmlStrEqual(type, BAD_CAST "token"))
2630        return (1);
2631    return (0);
2632}
2633
2634/**
2635 * xmlRelaxNGDefaultTypeCheck:
2636 * @data:  data needed for the library
2637 * @type:  the type name
2638 * @value:  the value to check
2639 * @node:  the node
2640 *
2641 * Check if the given type and value are validated by
2642 * the default datatype library.
2643 *
2644 * Returns 1 if yes, 0 if no and -1 in case of error.
2645 */
2646static int
2647xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2648                           const xmlChar * type ATTRIBUTE_UNUSED,
2649                           const xmlChar * value ATTRIBUTE_UNUSED,
2650                           void **result ATTRIBUTE_UNUSED,
2651                           xmlNodePtr node ATTRIBUTE_UNUSED)
2652{
2653    if (value == NULL)
2654        return (-1);
2655    if (xmlStrEqual(type, BAD_CAST "string"))
2656        return (1);
2657    if (xmlStrEqual(type, BAD_CAST "token")) {
2658        return (1);
2659    }
2660
2661    return (0);
2662}
2663
2664/**
2665 * xmlRelaxNGDefaultTypeCompare:
2666 * @data:  data needed for the library
2667 * @type:  the type name
2668 * @value1:  the first value
2669 * @value2:  the second value
2670 *
2671 * Compare two values accordingly a type from the default
2672 * datatype library.
2673 *
2674 * Returns 1 if yes, 0 if no and -1 in case of error.
2675 */
2676static int
2677xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2678                             const xmlChar * type,
2679                             const xmlChar * value1,
2680                             xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2681                             void *comp1 ATTRIBUTE_UNUSED,
2682                             const xmlChar * value2,
2683                             xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2684{
2685    int ret = -1;
2686
2687    if (xmlStrEqual(type, BAD_CAST "string")) {
2688        ret = xmlStrEqual(value1, value2);
2689    } else if (xmlStrEqual(type, BAD_CAST "token")) {
2690        if (!xmlStrEqual(value1, value2)) {
2691            xmlChar *nval, *nvalue;
2692
2693            /*
2694             * TODO: trivial optimizations are possible by
2695             * computing at compile-time
2696             */
2697            nval = xmlRelaxNGNormalize(NULL, value1);
2698            nvalue = xmlRelaxNGNormalize(NULL, value2);
2699
2700            if ((nval == NULL) || (nvalue == NULL))
2701                ret = -1;
2702            else if (xmlStrEqual(nval, nvalue))
2703                ret = 1;
2704            else
2705                ret = 0;
2706            if (nval != NULL)
2707                xmlFree(nval);
2708            if (nvalue != NULL)
2709                xmlFree(nvalue);
2710        } else
2711            ret = 1;
2712    }
2713    return (ret);
2714}
2715
2716static int xmlRelaxNGTypeInitialized = 0;
2717static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2718
2719/**
2720 * xmlRelaxNGFreeTypeLibrary:
2721 * @lib:  the type library structure
2722 * @namespace:  the URI bound to the library
2723 *
2724 * Free the structure associated to the type library
2725 */
2726static void
2727xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2728                          const xmlChar * namespace ATTRIBUTE_UNUSED)
2729{
2730    if (lib == NULL)
2731        return;
2732    if (lib->namespace != NULL)
2733        xmlFree((xmlChar *) lib->namespace);
2734    xmlFree(lib);
2735}
2736
2737/**
2738 * xmlRelaxNGRegisterTypeLibrary:
2739 * @namespace:  the URI bound to the library
2740 * @data:  data associated to the library
2741 * @have:  the provide function
2742 * @check:  the checking function
2743 * @comp:  the comparison function
2744 *
2745 * Register a new type library
2746 *
2747 * Returns 0 in case of success and -1 in case of error.
2748 */
2749static int
2750xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2751                              xmlRelaxNGTypeHave have,
2752                              xmlRelaxNGTypeCheck check,
2753                              xmlRelaxNGTypeCompare comp,
2754                              xmlRelaxNGFacetCheck facet,
2755                              xmlRelaxNGTypeFree freef)
2756{
2757    xmlRelaxNGTypeLibraryPtr lib;
2758    int ret;
2759
2760    if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2761        (check == NULL) || (comp == NULL))
2762        return (-1);
2763    if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2764        xmlGenericError(xmlGenericErrorContext,
2765                        "Relax-NG types library '%s' already registered\n",
2766                        namespace);
2767        return (-1);
2768    }
2769    lib =
2770        (xmlRelaxNGTypeLibraryPtr)
2771        xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2772    if (lib == NULL) {
2773        xmlRngVErrMemory(NULL, "adding types library\n");
2774        return (-1);
2775    }
2776    memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2777    lib->namespace = xmlStrdup(namespace);
2778    lib->data = data;
2779    lib->have = have;
2780    lib->comp = comp;
2781    lib->check = check;
2782    lib->facet = facet;
2783    lib->freef = freef;
2784    ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2785    if (ret < 0) {
2786        xmlGenericError(xmlGenericErrorContext,
2787                        "Relax-NG types library failed to register '%s'\n",
2788                        namespace);
2789        xmlRelaxNGFreeTypeLibrary(lib, namespace);
2790        return (-1);
2791    }
2792    return (0);
2793}
2794
2795/**
2796 * xmlRelaxNGInitTypes:
2797 *
2798 * Initilize the default type libraries.
2799 *
2800 * Returns 0 in case of success and -1 in case of error.
2801 */
2802int
2803xmlRelaxNGInitTypes(void)
2804{
2805    if (xmlRelaxNGTypeInitialized != 0)
2806        return (0);
2807    xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2808    if (xmlRelaxNGRegisteredTypes == NULL) {
2809        xmlGenericError(xmlGenericErrorContext,
2810                        "Failed to allocate sh table for Relax-NG types\n");
2811        return (-1);
2812    }
2813    xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2814                                  "http://www.w3.org/2001/XMLSchema-datatypes",
2815                                  NULL, xmlRelaxNGSchemaTypeHave,
2816                                  xmlRelaxNGSchemaTypeCheck,
2817                                  xmlRelaxNGSchemaTypeCompare,
2818                                  xmlRelaxNGSchemaFacetCheck,
2819                                  xmlRelaxNGSchemaFreeValue);
2820    xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2821                                  xmlRelaxNGDefaultTypeHave,
2822                                  xmlRelaxNGDefaultTypeCheck,
2823                                  xmlRelaxNGDefaultTypeCompare, NULL,
2824                                  NULL);
2825    xmlRelaxNGTypeInitialized = 1;
2826    return (0);
2827}
2828
2829/**
2830 * xmlRelaxNGCleanupTypes:
2831 *
2832 * Cleanup the default Schemas type library associated to RelaxNG
2833 */
2834void
2835xmlRelaxNGCleanupTypes(void)
2836{
2837    xmlSchemaCleanupTypes();
2838    if (xmlRelaxNGTypeInitialized == 0)
2839        return;
2840    xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2841                xmlRelaxNGFreeTypeLibrary);
2842    xmlRelaxNGTypeInitialized = 0;
2843}
2844
2845/************************************************************************
2846 * 									*
2847 * 		Compiling element content into regexp			*
2848 * 									*
2849 * Sometime the element content can be compiled into a pure regexp,	*
2850 * This allows a faster execution and streamability at that level	*
2851 * 									*
2852 ************************************************************************/
2853
2854static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2855                                xmlRelaxNGDefinePtr def);
2856
2857/**
2858 * xmlRelaxNGIsCompileable:
2859 * @define:  the definition to check
2860 *
2861 * Check if a definition is nullable.
2862 *
2863 * Returns 1 if yes, 0 if no and -1 in case of error
2864 */
2865static int
2866xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2867{
2868    int ret = -1;
2869
2870    if (def == NULL) {
2871        return (-1);
2872    }
2873    if ((def->type != XML_RELAXNG_ELEMENT) &&
2874        (def->dflags & IS_COMPILABLE))
2875        return (1);
2876    if ((def->type != XML_RELAXNG_ELEMENT) &&
2877        (def->dflags & IS_NOT_COMPILABLE))
2878        return (0);
2879    switch (def->type) {
2880        case XML_RELAXNG_NOOP:
2881            ret = xmlRelaxNGIsCompileable(def->content);
2882            break;
2883        case XML_RELAXNG_TEXT:
2884        case XML_RELAXNG_EMPTY:
2885            ret = 1;
2886            break;
2887        case XML_RELAXNG_ELEMENT:
2888            /*
2889             * Check if the element content is compileable
2890             */
2891            if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2892                ((def->dflags & IS_COMPILABLE) == 0)) {
2893                xmlRelaxNGDefinePtr list;
2894
2895                list = def->content;
2896                while (list != NULL) {
2897                    ret = xmlRelaxNGIsCompileable(list);
2898                    if (ret != 1)
2899                        break;
2900                    list = list->next;
2901                }
2902		/*
2903		 * Because the routine is recursive, we must guard against
2904		 * discovering both COMPILABLE and NOT_COMPILABLE
2905		 */
2906                if (ret == 0) {
2907		    def->dflags &= ~IS_COMPILABLE;
2908                    def->dflags |= IS_NOT_COMPILABLE;
2909		}
2910                if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
2911                    def->dflags |= IS_COMPILABLE;
2912#ifdef DEBUG_COMPILE
2913                if (ret == 1) {
2914                    xmlGenericError(xmlGenericErrorContext,
2915                                    "element content for %s is compilable\n",
2916                                    def->name);
2917                } else if (ret == 0) {
2918                    xmlGenericError(xmlGenericErrorContext,
2919                                    "element content for %s is not compilable\n",
2920                                    def->name);
2921                } else {
2922                    xmlGenericError(xmlGenericErrorContext,
2923                                    "Problem in RelaxNGIsCompileable for element %s\n",
2924                                    def->name);
2925                }
2926#endif
2927            }
2928            /*
2929             * All elements return a compileable status unless they
2930             * are generic like anyName
2931             */
2932            if ((def->nameClass != NULL) || (def->name == NULL))
2933                ret = 0;
2934            else
2935                ret = 1;
2936            return (ret);
2937        case XML_RELAXNG_REF:
2938        case XML_RELAXNG_EXTERNALREF:
2939        case XML_RELAXNG_PARENTREF:
2940            if (def->depth == -20) {
2941                return (1);
2942            } else {
2943                xmlRelaxNGDefinePtr list;
2944
2945                def->depth = -20;
2946                list = def->content;
2947                while (list != NULL) {
2948                    ret = xmlRelaxNGIsCompileable(list);
2949                    if (ret != 1)
2950                        break;
2951                    list = list->next;
2952                }
2953            }
2954            break;
2955        case XML_RELAXNG_START:
2956        case XML_RELAXNG_OPTIONAL:
2957        case XML_RELAXNG_ZEROORMORE:
2958        case XML_RELAXNG_ONEORMORE:
2959        case XML_RELAXNG_CHOICE:
2960        case XML_RELAXNG_GROUP:
2961        case XML_RELAXNG_DEF:{
2962                xmlRelaxNGDefinePtr list;
2963
2964                list = def->content;
2965                while (list != NULL) {
2966                    ret = xmlRelaxNGIsCompileable(list);
2967                    if (ret != 1)
2968                        break;
2969                    list = list->next;
2970                }
2971                break;
2972            }
2973        case XML_RELAXNG_EXCEPT:
2974        case XML_RELAXNG_ATTRIBUTE:
2975        case XML_RELAXNG_INTERLEAVE:
2976        case XML_RELAXNG_DATATYPE:
2977        case XML_RELAXNG_LIST:
2978        case XML_RELAXNG_PARAM:
2979        case XML_RELAXNG_VALUE:
2980        case XML_RELAXNG_NOT_ALLOWED:
2981            ret = 0;
2982            break;
2983    }
2984    if (ret == 0)
2985        def->dflags |= IS_NOT_COMPILABLE;
2986    if (ret == 1)
2987        def->dflags |= IS_COMPILABLE;
2988#ifdef DEBUG_COMPILE
2989    if (ret == 1) {
2990        xmlGenericError(xmlGenericErrorContext,
2991                        "RelaxNGIsCompileable %s : true\n",
2992                        xmlRelaxNGDefName(def));
2993    } else if (ret == 0) {
2994        xmlGenericError(xmlGenericErrorContext,
2995                        "RelaxNGIsCompileable %s : false\n",
2996                        xmlRelaxNGDefName(def));
2997    } else {
2998        xmlGenericError(xmlGenericErrorContext,
2999                        "Problem in RelaxNGIsCompileable %s\n",
3000                        xmlRelaxNGDefName(def));
3001    }
3002#endif
3003    return (ret);
3004}
3005
3006/**
3007 * xmlRelaxNGCompile:
3008 * ctxt:  the RelaxNG parser context
3009 * @define:  the definition tree to compile
3010 *
3011 * Compile the set of definitions, it works recursively, till the
3012 * element boundaries, where it tries to compile the content if possible
3013 *
3014 * Returns 0 if success and -1 in case of error
3015 */
3016static int
3017xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3018{
3019    int ret = 0;
3020    xmlRelaxNGDefinePtr list;
3021
3022    if ((ctxt == NULL) || (def == NULL))
3023        return (-1);
3024
3025    switch (def->type) {
3026        case XML_RELAXNG_START:
3027            if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
3028                xmlAutomataPtr oldam = ctxt->am;
3029                xmlAutomataStatePtr oldstate = ctxt->state;
3030
3031                def->depth = -25;
3032
3033                list = def->content;
3034                ctxt->am = xmlNewAutomata();
3035                if (ctxt->am == NULL)
3036                    return (-1);
3037                ctxt->state = xmlAutomataGetInitState(ctxt->am);
3038                while (list != NULL) {
3039                    xmlRelaxNGCompile(ctxt, list);
3040                    list = list->next;
3041                }
3042                xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3043                def->contModel = xmlAutomataCompile(ctxt->am);
3044                xmlRegexpIsDeterminist(def->contModel);
3045
3046                xmlFreeAutomata(ctxt->am);
3047                ctxt->state = oldstate;
3048                ctxt->am = oldam;
3049            }
3050            break;
3051        case XML_RELAXNG_ELEMENT:
3052            if ((ctxt->am != NULL) && (def->name != NULL)) {
3053                ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3054                                                        ctxt->state, NULL,
3055                                                        def->name, def->ns,
3056                                                        def);
3057            }
3058            if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3059                xmlAutomataPtr oldam = ctxt->am;
3060                xmlAutomataStatePtr oldstate = ctxt->state;
3061
3062                def->depth = -25;
3063
3064                list = def->content;
3065                ctxt->am = xmlNewAutomata();
3066                if (ctxt->am == NULL)
3067                    return (-1);
3068                ctxt->state = xmlAutomataGetInitState(ctxt->am);
3069                while (list != NULL) {
3070                    xmlRelaxNGCompile(ctxt, list);
3071                    list = list->next;
3072                }
3073                xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3074                def->contModel = xmlAutomataCompile(ctxt->am);
3075                if (!xmlRegexpIsDeterminist(def->contModel)) {
3076                    /*
3077                     * we can only use the automata if it is determinist
3078                     */
3079                    xmlRegFreeRegexp(def->contModel);
3080                    def->contModel = NULL;
3081                }
3082                xmlFreeAutomata(ctxt->am);
3083                ctxt->state = oldstate;
3084                ctxt->am = oldam;
3085            } else {
3086                xmlAutomataPtr oldam = ctxt->am;
3087
3088                /*
3089                 * we can't build the content model for this element content
3090                 * but it still might be possible to build it for some of its
3091                 * children, recurse.
3092                 */
3093                ret = xmlRelaxNGTryCompile(ctxt, def);
3094                ctxt->am = oldam;
3095            }
3096            break;
3097        case XML_RELAXNG_NOOP:
3098            ret = xmlRelaxNGCompile(ctxt, def->content);
3099            break;
3100        case XML_RELAXNG_OPTIONAL:{
3101                xmlAutomataStatePtr oldstate = ctxt->state;
3102
3103                xmlRelaxNGCompile(ctxt, def->content);
3104                xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3105                break;
3106            }
3107        case XML_RELAXNG_ZEROORMORE:{
3108                xmlAutomataStatePtr oldstate;
3109
3110                ctxt->state =
3111                    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3112                oldstate = ctxt->state;
3113                list = def->content;
3114                while (list != NULL) {
3115                    xmlRelaxNGCompile(ctxt, list);
3116                    list = list->next;
3117                }
3118                xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3119                ctxt->state =
3120                    xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3121                break;
3122            }
3123        case XML_RELAXNG_ONEORMORE:{
3124                xmlAutomataStatePtr oldstate;
3125
3126                list = def->content;
3127                while (list != NULL) {
3128                    xmlRelaxNGCompile(ctxt, list);
3129                    list = list->next;
3130                }
3131                oldstate = ctxt->state;
3132                list = def->content;
3133                while (list != NULL) {
3134                    xmlRelaxNGCompile(ctxt, list);
3135                    list = list->next;
3136                }
3137                xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3138                ctxt->state =
3139                    xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3140                break;
3141            }
3142        case XML_RELAXNG_CHOICE:{
3143                xmlAutomataStatePtr target = NULL;
3144                xmlAutomataStatePtr oldstate = ctxt->state;
3145
3146                list = def->content;
3147                while (list != NULL) {
3148                    ctxt->state = oldstate;
3149                    ret = xmlRelaxNGCompile(ctxt, list);
3150                    if (ret != 0)
3151                        break;
3152                    if (target == NULL)
3153                        target = ctxt->state;
3154                    else {
3155                        xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3156                                              target);
3157                    }
3158                    list = list->next;
3159                }
3160                ctxt->state = target;
3161
3162                break;
3163            }
3164        case XML_RELAXNG_REF:
3165        case XML_RELAXNG_EXTERNALREF:
3166        case XML_RELAXNG_PARENTREF:
3167        case XML_RELAXNG_GROUP:
3168        case XML_RELAXNG_DEF:
3169            list = def->content;
3170            while (list != NULL) {
3171                ret = xmlRelaxNGCompile(ctxt, list);
3172                if (ret != 0)
3173                    break;
3174                list = list->next;
3175            }
3176            break;
3177        case XML_RELAXNG_TEXT:{
3178                xmlAutomataStatePtr oldstate;
3179
3180                ctxt->state =
3181                    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3182                oldstate = ctxt->state;
3183                xmlRelaxNGCompile(ctxt, def->content);
3184                xmlAutomataNewTransition(ctxt->am, ctxt->state,
3185                                         ctxt->state, BAD_CAST "#text",
3186                                         NULL);
3187                ctxt->state =
3188                    xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3189                break;
3190            }
3191        case XML_RELAXNG_EMPTY:
3192            ctxt->state =
3193                xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3194            break;
3195        case XML_RELAXNG_EXCEPT:
3196        case XML_RELAXNG_ATTRIBUTE:
3197        case XML_RELAXNG_INTERLEAVE:
3198        case XML_RELAXNG_NOT_ALLOWED:
3199        case XML_RELAXNG_DATATYPE:
3200        case XML_RELAXNG_LIST:
3201        case XML_RELAXNG_PARAM:
3202        case XML_RELAXNG_VALUE:
3203            /* This should not happen and generate an internal error */
3204            fprintf(stderr, "RNG internal error trying to compile %s\n",
3205                    xmlRelaxNGDefName(def));
3206            break;
3207    }
3208    return (ret);
3209}
3210
3211/**
3212 * xmlRelaxNGTryCompile:
3213 * ctxt:  the RelaxNG parser context
3214 * @define:  the definition tree to compile
3215 *
3216 * Try to compile the set of definitions, it works recursively,
3217 * possibly ignoring parts which cannot be compiled.
3218 *
3219 * Returns 0 if success and -1 in case of error
3220 */
3221static int
3222xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3223{
3224    int ret = 0;
3225    xmlRelaxNGDefinePtr list;
3226
3227    if ((ctxt == NULL) || (def == NULL))
3228        return (-1);
3229
3230    if ((def->type == XML_RELAXNG_START) ||
3231        (def->type == XML_RELAXNG_ELEMENT)) {
3232        ret = xmlRelaxNGIsCompileable(def);
3233        if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3234            ctxt->am = NULL;
3235            ret = xmlRelaxNGCompile(ctxt, def);
3236#ifdef DEBUG_PROGRESSIVE
3237            if (ret == 0) {
3238                if (def->type == XML_RELAXNG_START)
3239                    xmlGenericError(xmlGenericErrorContext,
3240                                    "compiled the start\n");
3241                else
3242                    xmlGenericError(xmlGenericErrorContext,
3243                                    "compiled element %s\n", def->name);
3244            } else {
3245                if (def->type == XML_RELAXNG_START)
3246                    xmlGenericError(xmlGenericErrorContext,
3247                                    "failed to compile the start\n");
3248                else
3249                    xmlGenericError(xmlGenericErrorContext,
3250                                    "failed to compile element %s\n",
3251                                    def->name);
3252            }
3253#endif
3254            return (ret);
3255        }
3256    }
3257    switch (def->type) {
3258        case XML_RELAXNG_NOOP:
3259            ret = xmlRelaxNGTryCompile(ctxt, def->content);
3260            break;
3261        case XML_RELAXNG_TEXT:
3262        case XML_RELAXNG_DATATYPE:
3263        case XML_RELAXNG_LIST:
3264        case XML_RELAXNG_PARAM:
3265        case XML_RELAXNG_VALUE:
3266        case XML_RELAXNG_EMPTY:
3267        case XML_RELAXNG_ELEMENT:
3268            ret = 0;
3269            break;
3270        case XML_RELAXNG_OPTIONAL:
3271        case XML_RELAXNG_ZEROORMORE:
3272        case XML_RELAXNG_ONEORMORE:
3273        case XML_RELAXNG_CHOICE:
3274        case XML_RELAXNG_GROUP:
3275        case XML_RELAXNG_DEF:
3276        case XML_RELAXNG_START:
3277        case XML_RELAXNG_REF:
3278        case XML_RELAXNG_EXTERNALREF:
3279        case XML_RELAXNG_PARENTREF:
3280            list = def->content;
3281            while (list != NULL) {
3282                ret = xmlRelaxNGTryCompile(ctxt, list);
3283                if (ret != 0)
3284                    break;
3285                list = list->next;
3286            }
3287            break;
3288        case XML_RELAXNG_EXCEPT:
3289        case XML_RELAXNG_ATTRIBUTE:
3290        case XML_RELAXNG_INTERLEAVE:
3291        case XML_RELAXNG_NOT_ALLOWED:
3292            ret = 0;
3293            break;
3294    }
3295    return (ret);
3296}
3297
3298/************************************************************************
3299 * 									*
3300 * 			Parsing functions				*
3301 * 									*
3302 ************************************************************************/
3303
3304static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3305                                                    ctxt, xmlNodePtr node);
3306static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3307                                                  ctxt, xmlNodePtr node);
3308static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3309                                                   ctxt, xmlNodePtr nodes,
3310                                                   int group);
3311static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3312                                                  ctxt, xmlNodePtr node);
3313static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3314                                             xmlNodePtr node);
3315static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3316                                         xmlNodePtr nodes);
3317static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3318                                                    ctxt, xmlNodePtr node,
3319                                                    xmlRelaxNGDefinePtr
3320                                                    def);
3321static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3322                                                   ctxt, xmlNodePtr nodes);
3323static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3324                                  xmlRelaxNGDefinePtr define,
3325                                  xmlNodePtr elem);
3326
3327
3328#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3329
3330/**
3331 * xmlRelaxNGIsNullable:
3332 * @define:  the definition to verify
3333 *
3334 * Check if a definition is nullable.
3335 *
3336 * Returns 1 if yes, 0 if no and -1 in case of error
3337 */
3338static int
3339xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3340{
3341    int ret;
3342
3343    if (define == NULL)
3344        return (-1);
3345
3346    if (define->dflags & IS_NULLABLE)
3347        return (1);
3348    if (define->dflags & IS_NOT_NULLABLE)
3349        return (0);
3350    switch (define->type) {
3351        case XML_RELAXNG_EMPTY:
3352        case XML_RELAXNG_TEXT:
3353            ret = 1;
3354            break;
3355        case XML_RELAXNG_NOOP:
3356        case XML_RELAXNG_DEF:
3357        case XML_RELAXNG_REF:
3358        case XML_RELAXNG_EXTERNALREF:
3359        case XML_RELAXNG_PARENTREF:
3360        case XML_RELAXNG_ONEORMORE:
3361            ret = xmlRelaxNGIsNullable(define->content);
3362            break;
3363        case XML_RELAXNG_EXCEPT:
3364        case XML_RELAXNG_NOT_ALLOWED:
3365        case XML_RELAXNG_ELEMENT:
3366        case XML_RELAXNG_DATATYPE:
3367        case XML_RELAXNG_PARAM:
3368        case XML_RELAXNG_VALUE:
3369        case XML_RELAXNG_LIST:
3370        case XML_RELAXNG_ATTRIBUTE:
3371            ret = 0;
3372            break;
3373        case XML_RELAXNG_CHOICE:{
3374                xmlRelaxNGDefinePtr list = define->content;
3375
3376                while (list != NULL) {
3377                    ret = xmlRelaxNGIsNullable(list);
3378                    if (ret != 0)
3379                        goto done;
3380                    list = list->next;
3381                }
3382                ret = 0;
3383                break;
3384            }
3385        case XML_RELAXNG_START:
3386        case XML_RELAXNG_INTERLEAVE:
3387        case XML_RELAXNG_GROUP:{
3388                xmlRelaxNGDefinePtr list = define->content;
3389
3390                while (list != NULL) {
3391                    ret = xmlRelaxNGIsNullable(list);
3392                    if (ret != 1)
3393                        goto done;
3394                    list = list->next;
3395                }
3396                return (1);
3397            }
3398        default:
3399            return (-1);
3400    }
3401  done:
3402    if (ret == 0)
3403        define->dflags |= IS_NOT_NULLABLE;
3404    if (ret == 1)
3405        define->dflags |= IS_NULLABLE;
3406    return (ret);
3407}
3408
3409/**
3410 * xmlRelaxNGIsBlank:
3411 * @str:  a string
3412 *
3413 * Check if a string is ignorable c.f. 4.2. Whitespace
3414 *
3415 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3416 */
3417static int
3418xmlRelaxNGIsBlank(xmlChar * str)
3419{
3420    if (str == NULL)
3421        return (1);
3422    while (*str != 0) {
3423        if (!(IS_BLANK_CH(*str)))
3424            return (0);
3425        str++;
3426    }
3427    return (1);
3428}
3429
3430/**
3431 * xmlRelaxNGGetDataTypeLibrary:
3432 * @ctxt:  a Relax-NG parser context
3433 * @node:  the current data or value element
3434 *
3435 * Applies algorithm from 4.3. datatypeLibrary attribute
3436 *
3437 * Returns the datatypeLibary value or NULL if not found
3438 */
3439static xmlChar *
3440xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3441                             xmlNodePtr node)
3442{
3443    xmlChar *ret, *escape;
3444
3445    if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3446        ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3447        if (ret != NULL) {
3448            if (ret[0] == 0) {
3449                xmlFree(ret);
3450                return (NULL);
3451            }
3452            escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3453            if (escape == NULL) {
3454                return (ret);
3455            }
3456            xmlFree(ret);
3457            return (escape);
3458        }
3459    }
3460    node = node->parent;
3461    while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3462        ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3463        if (ret != NULL) {
3464            if (ret[0] == 0) {
3465                xmlFree(ret);
3466                return (NULL);
3467            }
3468            escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3469            if (escape == NULL) {
3470                return (ret);
3471            }
3472            xmlFree(ret);
3473            return (escape);
3474        }
3475        node = node->parent;
3476    }
3477    return (NULL);
3478}
3479
3480/**
3481 * xmlRelaxNGParseValue:
3482 * @ctxt:  a Relax-NG parser context
3483 * @node:  the data node.
3484 *
3485 * parse the content of a RelaxNG value node.
3486 *
3487 * Returns the definition pointer or NULL in case of error
3488 */
3489static xmlRelaxNGDefinePtr
3490xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3491{
3492    xmlRelaxNGDefinePtr def = NULL;
3493    xmlRelaxNGTypeLibraryPtr lib = NULL;
3494    xmlChar *type;
3495    xmlChar *library;
3496    int success = 0;
3497
3498    def = xmlRelaxNGNewDefine(ctxt, node);
3499    if (def == NULL)
3500        return (NULL);
3501    def->type = XML_RELAXNG_VALUE;
3502
3503    type = xmlGetProp(node, BAD_CAST "type");
3504    if (type != NULL) {
3505        xmlRelaxNGNormExtSpace(type);
3506        if (xmlValidateNCName(type, 0)) {
3507            xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3508                       "value type '%s' is not an NCName\n", type, NULL);
3509        }
3510        library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3511        if (library == NULL)
3512            library =
3513                xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3514
3515        def->name = type;
3516        def->ns = library;
3517
3518        lib = (xmlRelaxNGTypeLibraryPtr)
3519            xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3520        if (lib == NULL) {
3521            xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3522                       "Use of unregistered type library '%s'\n", library,
3523                       NULL);
3524            def->data = NULL;
3525        } else {
3526            def->data = lib;
3527            if (lib->have == NULL) {
3528                xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3529                           "Internal error with type library '%s': no 'have'\n",
3530                           library, NULL);
3531            } else {
3532                success = lib->have(lib->data, def->name);
3533                if (success != 1) {
3534                    xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3535                               "Error type '%s' is not exported by type library '%s'\n",
3536                               def->name, library);
3537                }
3538            }
3539        }
3540    }
3541    if (node->children == NULL) {
3542        def->value = xmlStrdup(BAD_CAST "");
3543    } else if (((node->children->type != XML_TEXT_NODE) &&
3544                (node->children->type != XML_CDATA_SECTION_NODE)) ||
3545               (node->children->next != NULL)) {
3546        xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3547                   "Expecting a single text value for <value>content\n",
3548                   NULL, NULL);
3549    } else if (def != NULL) {
3550        def->value = xmlNodeGetContent(node);
3551        if (def->value == NULL) {
3552            xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3553                       "Element <value> has no content\n", NULL, NULL);
3554        } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3555            void *val = NULL;
3556
3557            success =
3558                lib->check(lib->data, def->name, def->value, &val, node);
3559            if (success != 1) {
3560                xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3561                           "Value '%s' is not acceptable for type '%s'\n",
3562                           def->value, def->name);
3563            } else {
3564                if (val != NULL)
3565                    def->attrs = val;
3566            }
3567        }
3568    }
3569    return (def);
3570}
3571
3572/**
3573 * xmlRelaxNGParseData:
3574 * @ctxt:  a Relax-NG parser context
3575 * @node:  the data node.
3576 *
3577 * parse the content of a RelaxNG data node.
3578 *
3579 * Returns the definition pointer or NULL in case of error
3580 */
3581static xmlRelaxNGDefinePtr
3582xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3583{
3584    xmlRelaxNGDefinePtr def = NULL, except;
3585    xmlRelaxNGDefinePtr param, lastparam = NULL;
3586    xmlRelaxNGTypeLibraryPtr lib;
3587    xmlChar *type;
3588    xmlChar *library;
3589    xmlNodePtr content;
3590    int tmp;
3591
3592    type = xmlGetProp(node, BAD_CAST "type");
3593    if (type == NULL) {
3594        xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3595                   NULL);
3596        return (NULL);
3597    }
3598    xmlRelaxNGNormExtSpace(type);
3599    if (xmlValidateNCName(type, 0)) {
3600        xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3601                   "data type '%s' is not an NCName\n", type, NULL);
3602    }
3603    library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3604    if (library == NULL)
3605        library =
3606            xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3607
3608    def = xmlRelaxNGNewDefine(ctxt, node);
3609    if (def == NULL) {
3610        xmlFree(type);
3611        return (NULL);
3612    }
3613    def->type = XML_RELAXNG_DATATYPE;
3614    def->name = type;
3615    def->ns = library;
3616
3617    lib = (xmlRelaxNGTypeLibraryPtr)
3618        xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3619    if (lib == NULL) {
3620        xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3621                   "Use of unregistered type library '%s'\n", library,
3622                   NULL);
3623        def->data = NULL;
3624    } else {
3625        def->data = lib;
3626        if (lib->have == NULL) {
3627            xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3628                       "Internal error with type library '%s': no 'have'\n",
3629                       library, NULL);
3630        } else {
3631            tmp = lib->have(lib->data, def->name);
3632            if (tmp != 1) {
3633                xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3634                           "Error type '%s' is not exported by type library '%s'\n",
3635                           def->name, library);
3636            } else
3637                if ((xmlStrEqual
3638                     (library,
3639                      BAD_CAST
3640                      "http://www.w3.org/2001/XMLSchema-datatypes"))
3641                    && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3642                        || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3643                ctxt->idref = 1;
3644            }
3645        }
3646    }
3647    content = node->children;
3648
3649    /*
3650     * Handle optional params
3651     */
3652    while (content != NULL) {
3653        if (!xmlStrEqual(content->name, BAD_CAST "param"))
3654            break;
3655        if (xmlStrEqual(library,
3656                        BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3657            xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3658                       "Type library '%s' does not allow type parameters\n",
3659                       library, NULL);
3660            content = content->next;
3661            while ((content != NULL) &&
3662                   (xmlStrEqual(content->name, BAD_CAST "param")))
3663                content = content->next;
3664        } else {
3665            param = xmlRelaxNGNewDefine(ctxt, node);
3666            if (param != NULL) {
3667                param->type = XML_RELAXNG_PARAM;
3668                param->name = xmlGetProp(content, BAD_CAST "name");
3669                if (param->name == NULL) {
3670                    xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3671                               "param has no name\n", NULL, NULL);
3672                }
3673                param->value = xmlNodeGetContent(content);
3674                if (lastparam == NULL) {
3675                    def->attrs = lastparam = param;
3676                } else {
3677                    lastparam->next = param;
3678                    lastparam = param;
3679                }
3680                if (lib != NULL) {
3681                }
3682            }
3683            content = content->next;
3684        }
3685    }
3686    /*
3687     * Handle optional except
3688     */
3689    if ((content != NULL)
3690        && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3691        xmlNodePtr child;
3692        xmlRelaxNGDefinePtr tmp2, last = NULL;
3693
3694        except = xmlRelaxNGNewDefine(ctxt, node);
3695        if (except == NULL) {
3696            return (def);
3697        }
3698        except->type = XML_RELAXNG_EXCEPT;
3699        child = content->children;
3700	def->content = except;
3701        if (child == NULL) {
3702            xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3703                       "except has no content\n", NULL, NULL);
3704        }
3705        while (child != NULL) {
3706            tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3707            if (tmp2 != NULL) {
3708                if (last == NULL) {
3709                    except->content = last = tmp2;
3710                } else {
3711                    last->next = tmp2;
3712                    last = tmp2;
3713                }
3714            }
3715            child = child->next;
3716        }
3717        content = content->next;
3718    }
3719    /*
3720     * Check there is no unhandled data
3721     */
3722    if (content != NULL) {
3723        xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3724                   "Element data has unexpected content %s\n",
3725                   content->name, NULL);
3726    }
3727
3728    return (def);
3729}
3730
3731static const xmlChar *invalidName = BAD_CAST "\1";
3732
3733/**
3734 * xmlRelaxNGCompareNameClasses:
3735 * @defs1:  the first element/attribute defs
3736 * @defs2:  the second element/attribute defs
3737 * @name:  the restriction on the name
3738 * @ns:  the restriction on the namespace
3739 *
3740 * Compare the 2 lists of element definitions. The comparison is
3741 * that if both lists do not accept the same QNames, it returns 1
3742 * If the 2 lists can accept the same QName the comparison returns 0
3743 *
3744 * Returns 1 disttinct, 0 if equal
3745 */
3746static int
3747xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3748                             xmlRelaxNGDefinePtr def2)
3749{
3750    int ret = 1;
3751    xmlNode node;
3752    xmlNs ns;
3753    xmlRelaxNGValidCtxt ctxt;
3754
3755    memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3756
3757    ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3758
3759    if ((def1->type == XML_RELAXNG_ELEMENT) ||
3760        (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3761        if (def2->type == XML_RELAXNG_TEXT)
3762            return (1);
3763        if (def1->name != NULL) {
3764            node.name = def1->name;
3765        } else {
3766            node.name = invalidName;
3767        }
3768        if (def1->ns != NULL) {
3769            if (def1->ns[0] == 0) {
3770                node.ns = NULL;
3771            } else {
3772	        node.ns = &ns;
3773                ns.href = def1->ns;
3774            }
3775        } else {
3776            node.ns = NULL;
3777        }
3778        if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3779            if (def1->nameClass != NULL) {
3780                ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3781            } else {
3782                ret = 0;
3783            }
3784        } else {
3785            ret = 1;
3786        }
3787    } else if (def1->type == XML_RELAXNG_TEXT) {
3788        if (def2->type == XML_RELAXNG_TEXT)
3789            return (0);
3790        return (1);
3791    } else if (def1->type == XML_RELAXNG_EXCEPT) {
3792        TODO ret = 0;
3793    } else {
3794        TODO ret = 0;
3795    }
3796    if (ret == 0)
3797        return (ret);
3798    if ((def2->type == XML_RELAXNG_ELEMENT) ||
3799        (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3800        if (def2->name != NULL) {
3801            node.name = def2->name;
3802        } else {
3803            node.name = invalidName;
3804        }
3805        node.ns = &ns;
3806        if (def2->ns != NULL) {
3807            if (def2->ns[0] == 0) {
3808                node.ns = NULL;
3809            } else {
3810                ns.href = def2->ns;
3811            }
3812        } else {
3813            ns.href = invalidName;
3814        }
3815        if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3816            if (def2->nameClass != NULL) {
3817                ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3818            } else {
3819                ret = 0;
3820            }
3821        } else {
3822            ret = 1;
3823        }
3824    } else {
3825        TODO ret = 0;
3826    }
3827
3828    return (ret);
3829}
3830
3831/**
3832 * xmlRelaxNGCompareElemDefLists:
3833 * @ctxt:  a Relax-NG parser context
3834 * @defs1:  the first list of element/attribute defs
3835 * @defs2:  the second list of element/attribute defs
3836 *
3837 * Compare the 2 lists of element or attribute definitions. The comparison
3838 * is that if both lists do not accept the same QNames, it returns 1
3839 * If the 2 lists can accept the same QName the comparison returns 0
3840 *
3841 * Returns 1 disttinct, 0 if equal
3842 */
3843static int
3844xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3845                              ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3846                              xmlRelaxNGDefinePtr * def2)
3847{
3848    xmlRelaxNGDefinePtr *basedef2 = def2;
3849
3850    if ((def1 == NULL) || (def2 == NULL))
3851        return (1);
3852    if ((*def1 == NULL) || (*def2 == NULL))
3853        return (1);
3854    while (*def1 != NULL) {
3855        while ((*def2) != NULL) {
3856            if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3857                return (0);
3858            def2++;
3859        }
3860        def2 = basedef2;
3861        def1++;
3862    }
3863    return (1);
3864}
3865
3866/**
3867 * xmlRelaxNGGenerateAttributes:
3868 * @ctxt:  a Relax-NG parser context
3869 * @def:  the definition definition
3870 *
3871 * Check if the definition can only generate attributes
3872 *
3873 * Returns 1 if yes, 0 if no and -1 in case of error.
3874 */
3875static int
3876xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3877                             xmlRelaxNGDefinePtr def)
3878{
3879    xmlRelaxNGDefinePtr parent, cur, tmp;
3880
3881    /*
3882     * Don't run that check in case of error. Infinite recursion
3883     * becomes possible.
3884     */
3885    if (ctxt->nbErrors != 0)
3886        return (-1);
3887
3888    parent = NULL;
3889    cur = def;
3890    while (cur != NULL) {
3891        if ((cur->type == XML_RELAXNG_ELEMENT) ||
3892            (cur->type == XML_RELAXNG_TEXT) ||
3893            (cur->type == XML_RELAXNG_DATATYPE) ||
3894            (cur->type == XML_RELAXNG_PARAM) ||
3895            (cur->type == XML_RELAXNG_LIST) ||
3896            (cur->type == XML_RELAXNG_VALUE) ||
3897            (cur->type == XML_RELAXNG_EMPTY))
3898            return (0);
3899        if ((cur->type == XML_RELAXNG_CHOICE) ||
3900            (cur->type == XML_RELAXNG_INTERLEAVE) ||
3901            (cur->type == XML_RELAXNG_GROUP) ||
3902            (cur->type == XML_RELAXNG_ONEORMORE) ||
3903            (cur->type == XML_RELAXNG_ZEROORMORE) ||
3904            (cur->type == XML_RELAXNG_OPTIONAL) ||
3905            (cur->type == XML_RELAXNG_PARENTREF) ||
3906            (cur->type == XML_RELAXNG_EXTERNALREF) ||
3907            (cur->type == XML_RELAXNG_REF) ||
3908            (cur->type == XML_RELAXNG_DEF)) {
3909            if (cur->content != NULL) {
3910                parent = cur;
3911                cur = cur->content;
3912                tmp = cur;
3913                while (tmp != NULL) {
3914                    tmp->parent = parent;
3915                    tmp = tmp->next;
3916                }
3917                continue;
3918            }
3919        }
3920        if (cur == def)
3921            break;
3922        if (cur->next != NULL) {
3923            cur = cur->next;
3924            continue;
3925        }
3926        do {
3927            cur = cur->parent;
3928            if (cur == NULL)
3929                break;
3930            if (cur == def)
3931                return (1);
3932            if (cur->next != NULL) {
3933                cur = cur->next;
3934                break;
3935            }
3936        } while (cur != NULL);
3937    }
3938    return (1);
3939}
3940
3941/**
3942 * xmlRelaxNGGetElements:
3943 * @ctxt:  a Relax-NG parser context
3944 * @def:  the definition definition
3945 * @eora:  gather elements (0) or attributes (1)
3946 *
3947 * Compute the list of top elements a definition can generate
3948 *
3949 * Returns a list of elements or NULL if none was found.
3950 */
3951static xmlRelaxNGDefinePtr *
3952xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
3953                      xmlRelaxNGDefinePtr def, int eora)
3954{
3955    xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
3956    int len = 0;
3957    int max = 0;
3958
3959    /*
3960     * Don't run that check in case of error. Infinite recursion
3961     * becomes possible.
3962     */
3963    if (ctxt->nbErrors != 0)
3964        return (NULL);
3965
3966    parent = NULL;
3967    cur = def;
3968    while (cur != NULL) {
3969        if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3970                             (cur->type == XML_RELAXNG_TEXT))) ||
3971            ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3972            if (ret == NULL) {
3973                max = 10;
3974                ret = (xmlRelaxNGDefinePtr *)
3975                    xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3976                if (ret == NULL) {
3977                    xmlRngPErrMemory(ctxt, "getting element list\n");
3978                    return (NULL);
3979                }
3980            } else if (max <= len) {
3981	        xmlRelaxNGDefinePtr *temp;
3982
3983                max *= 2;
3984                temp = xmlRealloc(ret,
3985                               (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3986                if (temp == NULL) {
3987                    xmlRngPErrMemory(ctxt, "getting element list\n");
3988		    xmlFree(ret);
3989                    return (NULL);
3990                }
3991		ret = temp;
3992            }
3993            ret[len++] = cur;
3994            ret[len] = NULL;
3995        } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3996                   (cur->type == XML_RELAXNG_INTERLEAVE) ||
3997                   (cur->type == XML_RELAXNG_GROUP) ||
3998                   (cur->type == XML_RELAXNG_ONEORMORE) ||
3999                   (cur->type == XML_RELAXNG_ZEROORMORE) ||
4000                   (cur->type == XML_RELAXNG_OPTIONAL) ||
4001                   (cur->type == XML_RELAXNG_PARENTREF) ||
4002                   (cur->type == XML_RELAXNG_REF) ||
4003                   (cur->type == XML_RELAXNG_DEF) ||
4004		   (cur->type == XML_RELAXNG_EXTERNALREF)) {
4005            /*
4006             * Don't go within elements or attributes or string values.
4007             * Just gather the element top list
4008             */
4009            if (cur->content != NULL) {
4010                parent = cur;
4011                cur = cur->content;
4012                tmp = cur;
4013                while (tmp != NULL) {
4014                    tmp->parent = parent;
4015                    tmp = tmp->next;
4016                }
4017                continue;
4018            }
4019        }
4020        if (cur == def)
4021            break;
4022        if (cur->next != NULL) {
4023            cur = cur->next;
4024            continue;
4025        }
4026        do {
4027            cur = cur->parent;
4028            if (cur == NULL)
4029                break;
4030            if (cur == def)
4031                return (ret);
4032            if (cur->next != NULL) {
4033                cur = cur->next;
4034                break;
4035            }
4036        } while (cur != NULL);
4037    }
4038    return (ret);
4039}
4040
4041/**
4042 * xmlRelaxNGCheckChoiceDeterminism:
4043 * @ctxt:  a Relax-NG parser context
4044 * @def:  the choice definition
4045 *
4046 * Also used to find indeterministic pattern in choice
4047 */
4048static void
4049xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
4050                                 xmlRelaxNGDefinePtr def)
4051{
4052    xmlRelaxNGDefinePtr **list;
4053    xmlRelaxNGDefinePtr cur;
4054    int nbchild = 0, i, j, ret;
4055    int is_nullable = 0;
4056    int is_indeterminist = 0;
4057    xmlHashTablePtr triage = NULL;
4058    int is_triable = 1;
4059
4060    if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4061        return;
4062
4063    if (def->dflags & IS_PROCESSED)
4064        return;
4065
4066    /*
4067     * Don't run that check in case of error. Infinite recursion
4068     * becomes possible.
4069     */
4070    if (ctxt->nbErrors != 0)
4071        return;
4072
4073    is_nullable = xmlRelaxNGIsNullable(def);
4074
4075    cur = def->content;
4076    while (cur != NULL) {
4077        nbchild++;
4078        cur = cur->next;
4079    }
4080
4081    list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4082                                              sizeof(xmlRelaxNGDefinePtr
4083                                                     *));
4084    if (list == NULL) {
4085        xmlRngPErrMemory(ctxt, "building choice\n");
4086        return;
4087    }
4088    i = 0;
4089    /*
4090     * a bit strong but safe
4091     */
4092    if (is_nullable == 0) {
4093        triage = xmlHashCreate(10);
4094    } else {
4095        is_triable = 0;
4096    }
4097    cur = def->content;
4098    while (cur != NULL) {
4099        list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4100        if ((list[i] == NULL) || (list[i][0] == NULL)) {
4101            is_triable = 0;
4102        } else if (is_triable == 1) {
4103            xmlRelaxNGDefinePtr *tmp;
4104            int res;
4105
4106            tmp = list[i];
4107            while ((*tmp != NULL) && (is_triable == 1)) {
4108                if ((*tmp)->type == XML_RELAXNG_TEXT) {
4109                    res = xmlHashAddEntry2(triage,
4110                                           BAD_CAST "#text", NULL,
4111                                           (void *) cur);
4112                    if (res != 0)
4113                        is_triable = -1;
4114                } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4115                           ((*tmp)->name != NULL)) {
4116                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4117                        res = xmlHashAddEntry2(triage,
4118                                               (*tmp)->name, NULL,
4119                                               (void *) cur);
4120                    else
4121                        res = xmlHashAddEntry2(triage,
4122                                               (*tmp)->name, (*tmp)->ns,
4123                                               (void *) cur);
4124                    if (res != 0)
4125                        is_triable = -1;
4126                } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4127                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4128                        res = xmlHashAddEntry2(triage,
4129                                               BAD_CAST "#any", NULL,
4130                                               (void *) cur);
4131                    else
4132                        res = xmlHashAddEntry2(triage,
4133                                               BAD_CAST "#any", (*tmp)->ns,
4134                                               (void *) cur);
4135                    if (res != 0)
4136                        is_triable = -1;
4137                } else {
4138                    is_triable = -1;
4139                }
4140                tmp++;
4141            }
4142        }
4143        i++;
4144        cur = cur->next;
4145    }
4146
4147    for (i = 0; i < nbchild; i++) {
4148        if (list[i] == NULL)
4149            continue;
4150        for (j = 0; j < i; j++) {
4151            if (list[j] == NULL)
4152                continue;
4153            ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4154            if (ret == 0) {
4155                is_indeterminist = 1;
4156            }
4157        }
4158    }
4159    for (i = 0; i < nbchild; i++) {
4160        if (list[i] != NULL)
4161            xmlFree(list[i]);
4162    }
4163
4164    xmlFree(list);
4165    if (is_indeterminist) {
4166        def->dflags |= IS_INDETERMINIST;
4167    }
4168    if (is_triable == 1) {
4169        def->dflags |= IS_TRIABLE;
4170        def->data = triage;
4171    } else if (triage != NULL) {
4172        xmlHashFree(triage, NULL);
4173    }
4174    def->dflags |= IS_PROCESSED;
4175}
4176
4177/**
4178 * xmlRelaxNGCheckGroupAttrs:
4179 * @ctxt:  a Relax-NG parser context
4180 * @def:  the group definition
4181 *
4182 * Detects violations of rule 7.3
4183 */
4184static void
4185xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4186                          xmlRelaxNGDefinePtr def)
4187{
4188    xmlRelaxNGDefinePtr **list;
4189    xmlRelaxNGDefinePtr cur;
4190    int nbchild = 0, i, j, ret;
4191
4192    if ((def == NULL) ||
4193        ((def->type != XML_RELAXNG_GROUP) &&
4194         (def->type != XML_RELAXNG_ELEMENT)))
4195        return;
4196
4197    if (def->dflags & IS_PROCESSED)
4198        return;
4199
4200    /*
4201     * Don't run that check in case of error. Infinite recursion
4202     * becomes possible.
4203     */
4204    if (ctxt->nbErrors != 0)
4205        return;
4206
4207    cur = def->attrs;
4208    while (cur != NULL) {
4209        nbchild++;
4210        cur = cur->next;
4211    }
4212    cur = def->content;
4213    while (cur != NULL) {
4214        nbchild++;
4215        cur = cur->next;
4216    }
4217
4218    list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4219                                              sizeof(xmlRelaxNGDefinePtr
4220                                                     *));
4221    if (list == NULL) {
4222        xmlRngPErrMemory(ctxt, "building group\n");
4223        return;
4224    }
4225    i = 0;
4226    cur = def->attrs;
4227    while (cur != NULL) {
4228        list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4229        i++;
4230        cur = cur->next;
4231    }
4232    cur = def->content;
4233    while (cur != NULL) {
4234        list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4235        i++;
4236        cur = cur->next;
4237    }
4238
4239    for (i = 0; i < nbchild; i++) {
4240        if (list[i] == NULL)
4241            continue;
4242        for (j = 0; j < i; j++) {
4243            if (list[j] == NULL)
4244                continue;
4245            ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4246            if (ret == 0) {
4247                xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4248                           "Attributes conflicts in group\n", NULL, NULL);
4249            }
4250        }
4251    }
4252    for (i = 0; i < nbchild; i++) {
4253        if (list[i] != NULL)
4254            xmlFree(list[i]);
4255    }
4256
4257    xmlFree(list);
4258    def->dflags |= IS_PROCESSED;
4259}
4260
4261/**
4262 * xmlRelaxNGComputeInterleaves:
4263 * @def:  the interleave definition
4264 * @ctxt:  a Relax-NG parser context
4265 * @name:  the definition name
4266 *
4267 * A lot of work for preprocessing interleave definitions
4268 * is potentially needed to get a decent execution speed at runtime
4269 *   - trying to get a total order on the element nodes generated
4270 *     by the interleaves, order the list of interleave definitions
4271 *     following that order.
4272 *   - if <text/> is used to handle mixed content, it is better to
4273 *     flag this in the define and simplify the runtime checking
4274 *     algorithm
4275 */
4276static void
4277xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4278                             xmlRelaxNGParserCtxtPtr ctxt,
4279                             xmlChar * name ATTRIBUTE_UNUSED)
4280{
4281    xmlRelaxNGDefinePtr cur, *tmp;
4282
4283    xmlRelaxNGPartitionPtr partitions = NULL;
4284    xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4285    xmlRelaxNGInterleaveGroupPtr group;
4286    int i, j, ret, res;
4287    int nbgroups = 0;
4288    int nbchild = 0;
4289    int is_mixed = 0;
4290    int is_determinist = 1;
4291
4292    /*
4293     * Don't run that check in case of error. Infinite recursion
4294     * becomes possible.
4295     */
4296    if (ctxt->nbErrors != 0)
4297        return;
4298
4299#ifdef DEBUG_INTERLEAVE
4300    xmlGenericError(xmlGenericErrorContext,
4301                    "xmlRelaxNGComputeInterleaves(%s)\n", name);
4302#endif
4303    cur = def->content;
4304    while (cur != NULL) {
4305        nbchild++;
4306        cur = cur->next;
4307    }
4308
4309#ifdef DEBUG_INTERLEAVE
4310    xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
4311#endif
4312    groups = (xmlRelaxNGInterleaveGroupPtr *)
4313        xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4314    if (groups == NULL)
4315        goto error;
4316    cur = def->content;
4317    while (cur != NULL) {
4318        groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4319            xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4320        if (groups[nbgroups] == NULL)
4321            goto error;
4322        if (cur->type == XML_RELAXNG_TEXT)
4323            is_mixed++;
4324        groups[nbgroups]->rule = cur;
4325        groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4326        groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4327        nbgroups++;
4328        cur = cur->next;
4329    }
4330#ifdef DEBUG_INTERLEAVE
4331    xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
4332#endif
4333
4334    /*
4335     * Let's check that all rules makes a partitions according to 7.4
4336     */
4337    partitions = (xmlRelaxNGPartitionPtr)
4338        xmlMalloc(sizeof(xmlRelaxNGPartition));
4339    if (partitions == NULL)
4340        goto error;
4341    memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4342    partitions->nbgroups = nbgroups;
4343    partitions->triage = xmlHashCreate(nbgroups);
4344    for (i = 0; i < nbgroups; i++) {
4345        group = groups[i];
4346        for (j = i + 1; j < nbgroups; j++) {
4347            if (groups[j] == NULL)
4348                continue;
4349
4350            ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4351                                                groups[j]->defs);
4352            if (ret == 0) {
4353                xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4354                           "Element or text conflicts in interleave\n",
4355                           NULL, NULL);
4356            }
4357            ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4358                                                groups[j]->attrs);
4359            if (ret == 0) {
4360                xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4361                           "Attributes conflicts in interleave\n", NULL,
4362                           NULL);
4363            }
4364        }
4365        tmp = group->defs;
4366        if ((tmp != NULL) && (*tmp != NULL)) {
4367            while (*tmp != NULL) {
4368                if ((*tmp)->type == XML_RELAXNG_TEXT) {
4369                    res = xmlHashAddEntry2(partitions->triage,
4370                                           BAD_CAST "#text", NULL,
4371                                           (void *) (long) (i + 1));
4372                    if (res != 0)
4373                        is_determinist = -1;
4374                } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4375                           ((*tmp)->name != NULL)) {
4376                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4377                        res = xmlHashAddEntry2(partitions->triage,
4378                                               (*tmp)->name, NULL,
4379                                               (void *) (long) (i + 1));
4380                    else
4381                        res = xmlHashAddEntry2(partitions->triage,
4382                                               (*tmp)->name, (*tmp)->ns,
4383                                               (void *) (long) (i + 1));
4384                    if (res != 0)
4385                        is_determinist = -1;
4386                } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4387                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4388                        res = xmlHashAddEntry2(partitions->triage,
4389                                               BAD_CAST "#any", NULL,
4390                                               (void *) (long) (i + 1));
4391                    else
4392                        res = xmlHashAddEntry2(partitions->triage,
4393                                               BAD_CAST "#any", (*tmp)->ns,
4394                                               (void *) (long) (i + 1));
4395                    if ((*tmp)->nameClass != NULL)
4396                        is_determinist = 2;
4397                    if (res != 0)
4398                        is_determinist = -1;
4399                } else {
4400                    is_determinist = -1;
4401                }
4402                tmp++;
4403            }
4404        } else {
4405            is_determinist = 0;
4406        }
4407    }
4408    partitions->groups = groups;
4409
4410    /*
4411     * and save the partition list back in the def
4412     */
4413    def->data = partitions;
4414    if (is_mixed != 0)
4415        def->dflags |= IS_MIXED;
4416    if (is_determinist == 1)
4417        partitions->flags = IS_DETERMINIST;
4418    if (is_determinist == 2)
4419        partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4420    return;
4421
4422  error:
4423    xmlRngPErrMemory(ctxt, "in interleave computation\n");
4424    if (groups != NULL) {
4425        for (i = 0; i < nbgroups; i++)
4426            if (groups[i] != NULL) {
4427                if (groups[i]->defs != NULL)
4428                    xmlFree(groups[i]->defs);
4429                xmlFree(groups[i]);
4430            }
4431        xmlFree(groups);
4432    }
4433    xmlRelaxNGFreePartition(partitions);
4434}
4435
4436/**
4437 * xmlRelaxNGParseInterleave:
4438 * @ctxt:  a Relax-NG parser context
4439 * @node:  the data node.
4440 *
4441 * parse the content of a RelaxNG interleave node.
4442 *
4443 * Returns the definition pointer or NULL in case of error
4444 */
4445static xmlRelaxNGDefinePtr
4446xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4447{
4448    xmlRelaxNGDefinePtr def = NULL;
4449    xmlRelaxNGDefinePtr last = NULL, cur;
4450    xmlNodePtr child;
4451
4452    def = xmlRelaxNGNewDefine(ctxt, node);
4453    if (def == NULL) {
4454        return (NULL);
4455    }
4456    def->type = XML_RELAXNG_INTERLEAVE;
4457
4458    if (ctxt->interleaves == NULL)
4459        ctxt->interleaves = xmlHashCreate(10);
4460    if (ctxt->interleaves == NULL) {
4461        xmlRngPErrMemory(ctxt, "create interleaves\n");
4462    } else {
4463        char name[32];
4464
4465        snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4466        if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4467            xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4468                       "Failed to add %s to hash table\n",
4469		       (const xmlChar *) name, NULL);
4470        }
4471    }
4472    child = node->children;
4473    if (child == NULL) {
4474        xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4475                   "Element interleave is empty\n", NULL, NULL);
4476    }
4477    while (child != NULL) {
4478        if (IS_RELAXNG(child, "element")) {
4479            cur = xmlRelaxNGParseElement(ctxt, child);
4480        } else {
4481            cur = xmlRelaxNGParsePattern(ctxt, child);
4482        }
4483        if (cur != NULL) {
4484            cur->parent = def;
4485            if (last == NULL) {
4486                def->content = last = cur;
4487            } else {
4488                last->next = cur;
4489                last = cur;
4490            }
4491        }
4492        child = child->next;
4493    }
4494
4495    return (def);
4496}
4497
4498/**
4499 * xmlRelaxNGParseInclude:
4500 * @ctxt:  a Relax-NG parser context
4501 * @node:  the include node
4502 *
4503 * Integrate the content of an include node in the current grammar
4504 *
4505 * Returns 0 in case of success or -1 in case of error
4506 */
4507static int
4508xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4509{
4510    xmlRelaxNGIncludePtr incl;
4511    xmlNodePtr root;
4512    int ret = 0, tmp;
4513
4514    incl = node->psvi;
4515    if (incl == NULL) {
4516        xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4517                   "Include node has no data\n", NULL, NULL);
4518        return (-1);
4519    }
4520    root = xmlDocGetRootElement(incl->doc);
4521    if (root == NULL) {
4522        xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4523                   NULL, NULL);
4524        return (-1);
4525    }
4526    if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4527        xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4528                   "Include document root is not a grammar\n", NULL, NULL);
4529        return (-1);
4530    }
4531
4532    /*
4533     * Merge the definition from both the include and the internal list
4534     */
4535    if (root->children != NULL) {
4536        tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4537        if (tmp != 0)
4538            ret = -1;
4539    }
4540    if (node->children != NULL) {
4541        tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4542        if (tmp != 0)
4543            ret = -1;
4544    }
4545    return (ret);
4546}
4547
4548/**
4549 * xmlRelaxNGParseDefine:
4550 * @ctxt:  a Relax-NG parser context
4551 * @node:  the define node
4552 *
4553 * parse the content of a RelaxNG define element node.
4554 *
4555 * Returns 0 in case of success or -1 in case of error
4556 */
4557static int
4558xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4559{
4560    xmlChar *name;
4561    int ret = 0, tmp;
4562    xmlRelaxNGDefinePtr def;
4563    const xmlChar *olddefine;
4564
4565    name = xmlGetProp(node, BAD_CAST "name");
4566    if (name == NULL) {
4567        xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4568                   "define has no name\n", NULL, NULL);
4569    } else {
4570        xmlRelaxNGNormExtSpace(name);
4571        if (xmlValidateNCName(name, 0)) {
4572            xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4573                       "define name '%s' is not an NCName\n", name, NULL);
4574        }
4575        def = xmlRelaxNGNewDefine(ctxt, node);
4576        if (def == NULL) {
4577            xmlFree(name);
4578            return (-1);
4579        }
4580        def->type = XML_RELAXNG_DEF;
4581        def->name = name;
4582        if (node->children == NULL) {
4583            xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4584                       "define has no children\n", NULL, NULL);
4585        } else {
4586            olddefine = ctxt->define;
4587            ctxt->define = name;
4588            def->content =
4589                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4590            ctxt->define = olddefine;
4591        }
4592        if (ctxt->grammar->defs == NULL)
4593            ctxt->grammar->defs = xmlHashCreate(10);
4594        if (ctxt->grammar->defs == NULL) {
4595            xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4596                       "Could not create definition hash\n", NULL, NULL);
4597            ret = -1;
4598        } else {
4599            tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4600            if (tmp < 0) {
4601                xmlRelaxNGDefinePtr prev;
4602
4603                prev = xmlHashLookup(ctxt->grammar->defs, name);
4604                if (prev == NULL) {
4605                    xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4606                               "Internal error on define aggregation of %s\n",
4607                               name, NULL);
4608                    ret = -1;
4609                } else {
4610                    while (prev->nextHash != NULL)
4611                        prev = prev->nextHash;
4612                    prev->nextHash = def;
4613                }
4614            }
4615        }
4616    }
4617    return (ret);
4618}
4619
4620/**
4621 * xmlRelaxNGParseImportRef:
4622 * @payload: the parser context
4623 * @data: the current grammar
4624 * @name: the reference name
4625 *
4626 * Import import one references into the current grammar
4627 */
4628static void
4629xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
4630    xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4631    xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4632    int tmp;
4633
4634    tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4635    if (tmp < 0) {
4636        xmlRelaxNGDefinePtr prev;
4637
4638        prev = (xmlRelaxNGDefinePtr)
4639            xmlHashLookup(ctxt->grammar->refs, def->name);
4640        if (prev == NULL) {
4641            if (def->name != NULL) {
4642                xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4643                           "Error refs definitions '%s'\n",
4644                           def->name, NULL);
4645            } else {
4646                xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4647                           "Error refs definitions\n",
4648                           NULL, NULL);
4649            }
4650        } else {
4651            def->nextHash = prev->nextHash;
4652            prev->nextHash = def;
4653        }
4654    }
4655}
4656
4657/**
4658 * xmlRelaxNGParseImportRefs:
4659 * @ctxt: the parser context
4660 * @grammar: the sub grammar
4661 *
4662 * Import references from the subgrammar into the current grammar
4663 *
4664 * Returns 0 in case of success, -1 in case of failure
4665 */
4666static int
4667xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4668                          xmlRelaxNGGrammarPtr grammar) {
4669    if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4670        return(-1);
4671    if (grammar->refs == NULL)
4672        return(0);
4673    if (ctxt->grammar->refs == NULL)
4674        ctxt->grammar->refs = xmlHashCreate(10);
4675    if (ctxt->grammar->refs == NULL) {
4676        xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4677                   "Could not create references hash\n", NULL, NULL);
4678        return(-1);
4679    }
4680    xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
4681}
4682
4683/**
4684 * xmlRelaxNGProcessExternalRef:
4685 * @ctxt: the parser context
4686 * @node:  the externlRef node
4687 *
4688 * Process and compile an externlRef node
4689 *
4690 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4691 */
4692static xmlRelaxNGDefinePtr
4693xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4694{
4695    xmlRelaxNGDocumentPtr docu;
4696    xmlNodePtr root, tmp;
4697    xmlChar *ns;
4698    int newNs = 0, oldflags;
4699    xmlRelaxNGDefinePtr def;
4700
4701    docu = node->psvi;
4702    if (docu != NULL) {
4703        def = xmlRelaxNGNewDefine(ctxt, node);
4704        if (def == NULL)
4705            return (NULL);
4706        def->type = XML_RELAXNG_EXTERNALREF;
4707
4708        if (docu->content == NULL) {
4709            /*
4710             * Then do the parsing for good
4711             */
4712            root = xmlDocGetRootElement(docu->doc);
4713            if (root == NULL) {
4714                xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4715                           "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4716                           NULL);
4717                return (NULL);
4718            }
4719            /*
4720             * ns transmission rules
4721             */
4722            ns = xmlGetProp(root, BAD_CAST "ns");
4723            if (ns == NULL) {
4724                tmp = node;
4725                while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4726                    ns = xmlGetProp(tmp, BAD_CAST "ns");
4727                    if (ns != NULL) {
4728                        break;
4729                    }
4730                    tmp = tmp->parent;
4731                }
4732                if (ns != NULL) {
4733                    xmlSetProp(root, BAD_CAST "ns", ns);
4734                    newNs = 1;
4735                    xmlFree(ns);
4736                }
4737            } else {
4738                xmlFree(ns);
4739            }
4740
4741            /*
4742             * Parsing to get a precompiled schemas.
4743             */
4744            oldflags = ctxt->flags;
4745            ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4746            docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4747            ctxt->flags = oldflags;
4748            if ((docu->schema != NULL) &&
4749                (docu->schema->topgrammar != NULL)) {
4750                docu->content = docu->schema->topgrammar->start;
4751                if (docu->schema->topgrammar->refs)
4752                    xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
4753            }
4754
4755            /*
4756             * the externalRef may be reused in a different ns context
4757             */
4758            if (newNs == 1) {
4759                xmlUnsetProp(root, BAD_CAST "ns");
4760            }
4761        }
4762        def->content = docu->content;
4763    } else {
4764        def = NULL;
4765    }
4766    return (def);
4767}
4768
4769/**
4770 * xmlRelaxNGParsePattern:
4771 * @ctxt:  a Relax-NG parser context
4772 * @node:  the pattern node.
4773 *
4774 * parse the content of a RelaxNG pattern node.
4775 *
4776 * Returns the definition pointer or NULL in case of error or if no
4777 *     pattern is generated.
4778 */
4779static xmlRelaxNGDefinePtr
4780xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4781{
4782    xmlRelaxNGDefinePtr def = NULL;
4783
4784    if (node == NULL) {
4785        return (NULL);
4786    }
4787    if (IS_RELAXNG(node, "element")) {
4788        def = xmlRelaxNGParseElement(ctxt, node);
4789    } else if (IS_RELAXNG(node, "attribute")) {
4790        def = xmlRelaxNGParseAttribute(ctxt, node);
4791    } else if (IS_RELAXNG(node, "empty")) {
4792        def = xmlRelaxNGNewDefine(ctxt, node);
4793        if (def == NULL)
4794            return (NULL);
4795        def->type = XML_RELAXNG_EMPTY;
4796        if (node->children != NULL) {
4797            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4798                       "empty: had a child node\n", NULL, NULL);
4799        }
4800    } else if (IS_RELAXNG(node, "text")) {
4801        def = xmlRelaxNGNewDefine(ctxt, node);
4802        if (def == NULL)
4803            return (NULL);
4804        def->type = XML_RELAXNG_TEXT;
4805        if (node->children != NULL) {
4806            xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4807                       "text: had a child node\n", NULL, NULL);
4808        }
4809    } else if (IS_RELAXNG(node, "zeroOrMore")) {
4810        def = xmlRelaxNGNewDefine(ctxt, node);
4811        if (def == NULL)
4812            return (NULL);
4813        def->type = XML_RELAXNG_ZEROORMORE;
4814        if (node->children == NULL) {
4815            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4816                       "Element %s is empty\n", node->name, NULL);
4817        } else {
4818            def->content =
4819                xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4820        }
4821    } else if (IS_RELAXNG(node, "oneOrMore")) {
4822        def = xmlRelaxNGNewDefine(ctxt, node);
4823        if (def == NULL)
4824            return (NULL);
4825        def->type = XML_RELAXNG_ONEORMORE;
4826        if (node->children == NULL) {
4827            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4828                       "Element %s is empty\n", node->name, NULL);
4829        } else {
4830            def->content =
4831                xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4832        }
4833    } else if (IS_RELAXNG(node, "optional")) {
4834        def = xmlRelaxNGNewDefine(ctxt, node);
4835        if (def == NULL)
4836            return (NULL);
4837        def->type = XML_RELAXNG_OPTIONAL;
4838        if (node->children == NULL) {
4839            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4840                       "Element %s is empty\n", node->name, NULL);
4841        } else {
4842            def->content =
4843                xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4844        }
4845    } else if (IS_RELAXNG(node, "choice")) {
4846        def = xmlRelaxNGNewDefine(ctxt, node);
4847        if (def == NULL)
4848            return (NULL);
4849        def->type = XML_RELAXNG_CHOICE;
4850        if (node->children == NULL) {
4851            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4852                       "Element %s is empty\n", node->name, NULL);
4853        } else {
4854            def->content =
4855                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4856        }
4857    } else if (IS_RELAXNG(node, "group")) {
4858        def = xmlRelaxNGNewDefine(ctxt, node);
4859        if (def == NULL)
4860            return (NULL);
4861        def->type = XML_RELAXNG_GROUP;
4862        if (node->children == NULL) {
4863            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4864                       "Element %s is empty\n", node->name, NULL);
4865        } else {
4866            def->content =
4867                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4868        }
4869    } else if (IS_RELAXNG(node, "ref")) {
4870        def = xmlRelaxNGNewDefine(ctxt, node);
4871        if (def == NULL)
4872            return (NULL);
4873        def->type = XML_RELAXNG_REF;
4874        def->name = xmlGetProp(node, BAD_CAST "name");
4875        if (def->name == NULL) {
4876            xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4877                       NULL, NULL);
4878        } else {
4879            xmlRelaxNGNormExtSpace(def->name);
4880            if (xmlValidateNCName(def->name, 0)) {
4881                xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4882                           "ref name '%s' is not an NCName\n", def->name,
4883                           NULL);
4884            }
4885        }
4886        if (node->children != NULL) {
4887            xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4888                       NULL, NULL);
4889        }
4890        if (ctxt->grammar->refs == NULL)
4891            ctxt->grammar->refs = xmlHashCreate(10);
4892        if (ctxt->grammar->refs == NULL) {
4893            xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4894                       "Could not create references hash\n", NULL, NULL);
4895            def = NULL;
4896        } else {
4897            int tmp;
4898
4899            tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4900            if (tmp < 0) {
4901                xmlRelaxNGDefinePtr prev;
4902
4903                prev = (xmlRelaxNGDefinePtr)
4904                    xmlHashLookup(ctxt->grammar->refs, def->name);
4905                if (prev == NULL) {
4906                    if (def->name != NULL) {
4907		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4908				   "Error refs definitions '%s'\n",
4909				   def->name, NULL);
4910                    } else {
4911		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4912				   "Error refs definitions\n",
4913				   NULL, NULL);
4914                    }
4915                    def = NULL;
4916                } else {
4917                    def->nextHash = prev->nextHash;
4918                    prev->nextHash = def;
4919                }
4920            }
4921        }
4922    } else if (IS_RELAXNG(node, "data")) {
4923        def = xmlRelaxNGParseData(ctxt, node);
4924    } else if (IS_RELAXNG(node, "value")) {
4925        def = xmlRelaxNGParseValue(ctxt, node);
4926    } else if (IS_RELAXNG(node, "list")) {
4927        def = xmlRelaxNGNewDefine(ctxt, node);
4928        if (def == NULL)
4929            return (NULL);
4930        def->type = XML_RELAXNG_LIST;
4931        if (node->children == NULL) {
4932            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4933                       "Element %s is empty\n", node->name, NULL);
4934        } else {
4935            def->content =
4936                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4937        }
4938    } else if (IS_RELAXNG(node, "interleave")) {
4939        def = xmlRelaxNGParseInterleave(ctxt, node);
4940    } else if (IS_RELAXNG(node, "externalRef")) {
4941        def = xmlRelaxNGProcessExternalRef(ctxt, node);
4942    } else if (IS_RELAXNG(node, "notAllowed")) {
4943        def = xmlRelaxNGNewDefine(ctxt, node);
4944        if (def == NULL)
4945            return (NULL);
4946        def->type = XML_RELAXNG_NOT_ALLOWED;
4947        if (node->children != NULL) {
4948            xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4949                       "xmlRelaxNGParse: notAllowed element is not empty\n",
4950                       NULL, NULL);
4951        }
4952    } else if (IS_RELAXNG(node, "grammar")) {
4953        xmlRelaxNGGrammarPtr grammar, old;
4954        xmlRelaxNGGrammarPtr oldparent;
4955
4956#ifdef DEBUG_GRAMMAR
4957        xmlGenericError(xmlGenericErrorContext,
4958                        "Found <grammar> pattern\n");
4959#endif
4960
4961        oldparent = ctxt->parentgrammar;
4962        old = ctxt->grammar;
4963        ctxt->parentgrammar = old;
4964        grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4965        if (old != NULL) {
4966            ctxt->grammar = old;
4967            ctxt->parentgrammar = oldparent;
4968#if 0
4969            if (grammar != NULL) {
4970                grammar->next = old->next;
4971                old->next = grammar;
4972            }
4973#endif
4974        }
4975        if (grammar != NULL)
4976            def = grammar->start;
4977        else
4978            def = NULL;
4979    } else if (IS_RELAXNG(node, "parentRef")) {
4980        if (ctxt->parentgrammar == NULL) {
4981            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4982                       "Use of parentRef without a parent grammar\n", NULL,
4983                       NULL);
4984            return (NULL);
4985        }
4986        def = xmlRelaxNGNewDefine(ctxt, node);
4987        if (def == NULL)
4988            return (NULL);
4989        def->type = XML_RELAXNG_PARENTREF;
4990        def->name = xmlGetProp(node, BAD_CAST "name");
4991        if (def->name == NULL) {
4992            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4993                       "parentRef has no name\n", NULL, NULL);
4994        } else {
4995            xmlRelaxNGNormExtSpace(def->name);
4996            if (xmlValidateNCName(def->name, 0)) {
4997                xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4998                           "parentRef name '%s' is not an NCName\n",
4999                           def->name, NULL);
5000            }
5001        }
5002        if (node->children != NULL) {
5003            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
5004                       "parentRef is not empty\n", NULL, NULL);
5005        }
5006        if (ctxt->parentgrammar->refs == NULL)
5007            ctxt->parentgrammar->refs = xmlHashCreate(10);
5008        if (ctxt->parentgrammar->refs == NULL) {
5009            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5010                       "Could not create references hash\n", NULL, NULL);
5011            def = NULL;
5012        } else if (def->name != NULL) {
5013            int tmp;
5014
5015            tmp =
5016                xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
5017            if (tmp < 0) {
5018                xmlRelaxNGDefinePtr prev;
5019
5020                prev = (xmlRelaxNGDefinePtr)
5021                    xmlHashLookup(ctxt->parentgrammar->refs, def->name);
5022                if (prev == NULL) {
5023                    xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5024                               "Internal error parentRef definitions '%s'\n",
5025                               def->name, NULL);
5026                    def = NULL;
5027                } else {
5028                    def->nextHash = prev->nextHash;
5029                    prev->nextHash = def;
5030                }
5031            }
5032        }
5033    } else if (IS_RELAXNG(node, "mixed")) {
5034        if (node->children == NULL) {
5035            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
5036                       NULL, NULL);
5037            def = NULL;
5038        } else {
5039            def = xmlRelaxNGParseInterleave(ctxt, node);
5040            if (def != NULL) {
5041                xmlRelaxNGDefinePtr tmp;
5042
5043                if ((def->content != NULL) && (def->content->next != NULL)) {
5044                    tmp = xmlRelaxNGNewDefine(ctxt, node);
5045                    if (tmp != NULL) {
5046                        tmp->type = XML_RELAXNG_GROUP;
5047                        tmp->content = def->content;
5048                        def->content = tmp;
5049                    }
5050                }
5051
5052                tmp = xmlRelaxNGNewDefine(ctxt, node);
5053                if (tmp == NULL)
5054                    return (def);
5055                tmp->type = XML_RELAXNG_TEXT;
5056                tmp->next = def->content;
5057                def->content = tmp;
5058            }
5059        }
5060    } else {
5061        xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
5062                   "Unexpected node %s is not a pattern\n", node->name,
5063                   NULL);
5064        def = NULL;
5065    }
5066    return (def);
5067}
5068
5069/**
5070 * xmlRelaxNGParseAttribute:
5071 * @ctxt:  a Relax-NG parser context
5072 * @node:  the element node
5073 *
5074 * parse the content of a RelaxNG attribute node.
5075 *
5076 * Returns the definition pointer or NULL in case of error.
5077 */
5078static xmlRelaxNGDefinePtr
5079xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5080{
5081    xmlRelaxNGDefinePtr ret, cur;
5082    xmlNodePtr child;
5083    int old_flags;
5084
5085    ret = xmlRelaxNGNewDefine(ctxt, node);
5086    if (ret == NULL)
5087        return (NULL);
5088    ret->type = XML_RELAXNG_ATTRIBUTE;
5089    ret->parent = ctxt->def;
5090    child = node->children;
5091    if (child == NULL) {
5092        xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5093                   "xmlRelaxNGParseattribute: attribute has no children\n",
5094                   NULL, NULL);
5095        return (ret);
5096    }
5097    old_flags = ctxt->flags;
5098    ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
5099    cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5100    if (cur != NULL)
5101        child = child->next;
5102
5103    if (child != NULL) {
5104        cur = xmlRelaxNGParsePattern(ctxt, child);
5105        if (cur != NULL) {
5106            switch (cur->type) {
5107                case XML_RELAXNG_EMPTY:
5108                case XML_RELAXNG_NOT_ALLOWED:
5109                case XML_RELAXNG_TEXT:
5110                case XML_RELAXNG_ELEMENT:
5111                case XML_RELAXNG_DATATYPE:
5112                case XML_RELAXNG_VALUE:
5113                case XML_RELAXNG_LIST:
5114                case XML_RELAXNG_REF:
5115                case XML_RELAXNG_PARENTREF:
5116                case XML_RELAXNG_EXTERNALREF:
5117                case XML_RELAXNG_DEF:
5118                case XML_RELAXNG_ONEORMORE:
5119                case XML_RELAXNG_ZEROORMORE:
5120                case XML_RELAXNG_OPTIONAL:
5121                case XML_RELAXNG_CHOICE:
5122                case XML_RELAXNG_GROUP:
5123                case XML_RELAXNG_INTERLEAVE:
5124                case XML_RELAXNG_ATTRIBUTE:
5125                    ret->content = cur;
5126                    cur->parent = ret;
5127                    break;
5128                case XML_RELAXNG_START:
5129                case XML_RELAXNG_PARAM:
5130                case XML_RELAXNG_EXCEPT:
5131                    xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5132                               "attribute has invalid content\n", NULL,
5133                               NULL);
5134                    break;
5135                case XML_RELAXNG_NOOP:
5136                    xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5137                               "RNG Internal error, noop found in attribute\n",
5138                               NULL, NULL);
5139                    break;
5140            }
5141        }
5142        child = child->next;
5143    }
5144    if (child != NULL) {
5145        xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5146                   "attribute has multiple children\n", NULL, NULL);
5147    }
5148    ctxt->flags = old_flags;
5149    return (ret);
5150}
5151
5152/**
5153 * xmlRelaxNGParseExceptNameClass:
5154 * @ctxt:  a Relax-NG parser context
5155 * @node:  the except node
5156 * @attr:  1 if within an attribute, 0 if within an element
5157 *
5158 * parse the content of a RelaxNG nameClass node.
5159 *
5160 * Returns the definition pointer or NULL in case of error.
5161 */
5162static xmlRelaxNGDefinePtr
5163xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
5164                               xmlNodePtr node, int attr)
5165{
5166    xmlRelaxNGDefinePtr ret, cur, last = NULL;
5167    xmlNodePtr child;
5168
5169    if (!IS_RELAXNG(node, "except")) {
5170        xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5171                   "Expecting an except node\n", NULL, NULL);
5172        return (NULL);
5173    }
5174    if (node->next != NULL) {
5175        xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5176                   "exceptNameClass allows only a single except node\n",
5177                   NULL, NULL);
5178    }
5179    if (node->children == NULL) {
5180        xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5181                   NULL, NULL);
5182        return (NULL);
5183    }
5184
5185    ret = xmlRelaxNGNewDefine(ctxt, node);
5186    if (ret == NULL)
5187        return (NULL);
5188    ret->type = XML_RELAXNG_EXCEPT;
5189    child = node->children;
5190    while (child != NULL) {
5191        cur = xmlRelaxNGNewDefine(ctxt, child);
5192        if (cur == NULL)
5193            break;
5194        if (attr)
5195            cur->type = XML_RELAXNG_ATTRIBUTE;
5196        else
5197            cur->type = XML_RELAXNG_ELEMENT;
5198
5199        if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
5200            if (last == NULL) {
5201                ret->content = cur;
5202            } else {
5203                last->next = cur;
5204            }
5205            last = cur;
5206        }
5207        child = child->next;
5208    }
5209
5210    return (ret);
5211}
5212
5213/**
5214 * xmlRelaxNGParseNameClass:
5215 * @ctxt:  a Relax-NG parser context
5216 * @node:  the nameClass node
5217 * @def:  the current definition
5218 *
5219 * parse the content of a RelaxNG nameClass node.
5220 *
5221 * Returns the definition pointer or NULL in case of error.
5222 */
5223static xmlRelaxNGDefinePtr
5224xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5225                         xmlRelaxNGDefinePtr def)
5226{
5227    xmlRelaxNGDefinePtr ret, tmp;
5228    xmlChar *val;
5229
5230    ret = def;
5231    if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5232        (IS_RELAXNG(node, "nsName"))) {
5233        if ((def->type != XML_RELAXNG_ELEMENT) &&
5234            (def->type != XML_RELAXNG_ATTRIBUTE)) {
5235            ret = xmlRelaxNGNewDefine(ctxt, node);
5236            if (ret == NULL)
5237                return (NULL);
5238            ret->parent = def;
5239            if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5240                ret->type = XML_RELAXNG_ATTRIBUTE;
5241            else
5242                ret->type = XML_RELAXNG_ELEMENT;
5243        }
5244    }
5245    if (IS_RELAXNG(node, "name")) {
5246        val = xmlNodeGetContent(node);
5247        xmlRelaxNGNormExtSpace(val);
5248        if (xmlValidateNCName(val, 0)) {
5249	    if (node->parent != NULL)
5250		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5251			   "Element %s name '%s' is not an NCName\n",
5252			   node->parent->name, val);
5253	    else
5254		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5255			   "name '%s' is not an NCName\n",
5256			   val, NULL);
5257        }
5258        ret->name = val;
5259        val = xmlGetProp(node, BAD_CAST "ns");
5260        ret->ns = val;
5261        if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5262            (val != NULL) &&
5263            (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5264	    xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5265                        "Attribute with namespace '%s' is not allowed\n",
5266                        val, NULL);
5267        }
5268        if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5269            (val != NULL) &&
5270            (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5271	    xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5272                       "Attribute with QName 'xmlns' is not allowed\n",
5273                       val, NULL);
5274        }
5275    } else if (IS_RELAXNG(node, "anyName")) {
5276        ret->name = NULL;
5277        ret->ns = NULL;
5278        if (node->children != NULL) {
5279            ret->nameClass =
5280                xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5281                                               (def->type ==
5282                                                XML_RELAXNG_ATTRIBUTE));
5283        }
5284    } else if (IS_RELAXNG(node, "nsName")) {
5285        ret->name = NULL;
5286        ret->ns = xmlGetProp(node, BAD_CAST "ns");
5287        if (ret->ns == NULL) {
5288            xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5289                       "nsName has no ns attribute\n", NULL, NULL);
5290        }
5291        if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5292            (ret->ns != NULL) &&
5293            (xmlStrEqual
5294             (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5295            xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5296                       "Attribute with namespace '%s' is not allowed\n",
5297                       ret->ns, NULL);
5298        }
5299        if (node->children != NULL) {
5300            ret->nameClass =
5301                xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5302                                               (def->type ==
5303                                                XML_RELAXNG_ATTRIBUTE));
5304        }
5305    } else if (IS_RELAXNG(node, "choice")) {
5306        xmlNodePtr child;
5307        xmlRelaxNGDefinePtr last = NULL;
5308
5309        ret = xmlRelaxNGNewDefine(ctxt, node);
5310        if (ret == NULL)
5311            return (NULL);
5312        ret->parent = def;
5313        ret->type = XML_RELAXNG_CHOICE;
5314
5315        if (node->children == NULL) {
5316            xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5317                       "Element choice is empty\n", NULL, NULL);
5318        } else {
5319
5320            child = node->children;
5321            while (child != NULL) {
5322                tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5323                if (tmp != NULL) {
5324                    if (last == NULL) {
5325                        last = ret->nameClass = tmp;
5326                    } else {
5327                        last->next = tmp;
5328                        last = tmp;
5329                    }
5330                }
5331                child = child->next;
5332            }
5333        }
5334    } else {
5335        xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5336                   "expecting name, anyName, nsName or choice : got %s\n",
5337                   node->name, NULL);
5338        return (NULL);
5339    }
5340    if (ret != def) {
5341        if (def->nameClass == NULL) {
5342            def->nameClass = ret;
5343        } else {
5344            tmp = def->nameClass;
5345            while (tmp->next != NULL) {
5346                tmp = tmp->next;
5347            }
5348            tmp->next = ret;
5349        }
5350    }
5351    return (ret);
5352}
5353
5354/**
5355 * xmlRelaxNGParseElement:
5356 * @ctxt:  a Relax-NG parser context
5357 * @node:  the element node
5358 *
5359 * parse the content of a RelaxNG element node.
5360 *
5361 * Returns the definition pointer or NULL in case of error.
5362 */
5363static xmlRelaxNGDefinePtr
5364xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5365{
5366    xmlRelaxNGDefinePtr ret, cur, last;
5367    xmlNodePtr child;
5368    const xmlChar *olddefine;
5369
5370    ret = xmlRelaxNGNewDefine(ctxt, node);
5371    if (ret == NULL)
5372        return (NULL);
5373    ret->type = XML_RELAXNG_ELEMENT;
5374    ret->parent = ctxt->def;
5375    child = node->children;
5376    if (child == NULL) {
5377        xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5378                   "xmlRelaxNGParseElement: element has no children\n",
5379                   NULL, NULL);
5380        return (ret);
5381    }
5382    cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5383    if (cur != NULL)
5384        child = child->next;
5385
5386    if (child == NULL) {
5387        xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5388                   "xmlRelaxNGParseElement: element has no content\n",
5389                   NULL, NULL);
5390        return (ret);
5391    }
5392    olddefine = ctxt->define;
5393    ctxt->define = NULL;
5394    last = NULL;
5395    while (child != NULL) {
5396        cur = xmlRelaxNGParsePattern(ctxt, child);
5397        if (cur != NULL) {
5398            cur->parent = ret;
5399            switch (cur->type) {
5400                case XML_RELAXNG_EMPTY:
5401                case XML_RELAXNG_NOT_ALLOWED:
5402                case XML_RELAXNG_TEXT:
5403                case XML_RELAXNG_ELEMENT:
5404                case XML_RELAXNG_DATATYPE:
5405                case XML_RELAXNG_VALUE:
5406                case XML_RELAXNG_LIST:
5407                case XML_RELAXNG_REF:
5408                case XML_RELAXNG_PARENTREF:
5409                case XML_RELAXNG_EXTERNALREF:
5410                case XML_RELAXNG_DEF:
5411                case XML_RELAXNG_ZEROORMORE:
5412                case XML_RELAXNG_ONEORMORE:
5413                case XML_RELAXNG_OPTIONAL:
5414                case XML_RELAXNG_CHOICE:
5415                case XML_RELAXNG_GROUP:
5416                case XML_RELAXNG_INTERLEAVE:
5417                    if (last == NULL) {
5418                        ret->content = last = cur;
5419                    } else {
5420                        if ((last->type == XML_RELAXNG_ELEMENT) &&
5421                            (ret->content == last)) {
5422                            ret->content = xmlRelaxNGNewDefine(ctxt, node);
5423                            if (ret->content != NULL) {
5424                                ret->content->type = XML_RELAXNG_GROUP;
5425                                ret->content->content = last;
5426                            } else {
5427                                ret->content = last;
5428                            }
5429                        }
5430                        last->next = cur;
5431                        last = cur;
5432                    }
5433                    break;
5434                case XML_RELAXNG_ATTRIBUTE:
5435                    cur->next = ret->attrs;
5436                    ret->attrs = cur;
5437                    break;
5438                case XML_RELAXNG_START:
5439                    xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5440                               "RNG Internal error, start found in element\n",
5441                               NULL, NULL);
5442                    break;
5443                case XML_RELAXNG_PARAM:
5444                    xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5445                               "RNG Internal error, param found in element\n",
5446                               NULL, NULL);
5447                    break;
5448                case XML_RELAXNG_EXCEPT:
5449                    xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5450                               "RNG Internal error, except found in element\n",
5451                               NULL, NULL);
5452                    break;
5453                case XML_RELAXNG_NOOP:
5454                    xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5455                               "RNG Internal error, noop found in element\n",
5456                               NULL, NULL);
5457                    break;
5458            }
5459        }
5460        child = child->next;
5461    }
5462    ctxt->define = olddefine;
5463    return (ret);
5464}
5465
5466/**
5467 * xmlRelaxNGParsePatterns:
5468 * @ctxt:  a Relax-NG parser context
5469 * @nodes:  list of nodes
5470 * @group:  use an implicit <group> for elements
5471 *
5472 * parse the content of a RelaxNG start node.
5473 *
5474 * Returns the definition pointer or NULL in case of error.
5475 */
5476static xmlRelaxNGDefinePtr
5477xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5478                        int group)
5479{
5480    xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
5481
5482    parent = ctxt->def;
5483    while (nodes != NULL) {
5484        if (IS_RELAXNG(nodes, "element")) {
5485            cur = xmlRelaxNGParseElement(ctxt, nodes);
5486            if (def == NULL) {
5487                def = last = cur;
5488            } else {
5489                if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5490                    (def == last)) {
5491                    def = xmlRelaxNGNewDefine(ctxt, nodes);
5492                    def->type = XML_RELAXNG_GROUP;
5493                    def->content = last;
5494                }
5495                last->next = cur;
5496                last = cur;
5497            }
5498            cur->parent = parent;
5499        } else {
5500            cur = xmlRelaxNGParsePattern(ctxt, nodes);
5501            if (cur != NULL) {
5502                if (def == NULL) {
5503                    def = last = cur;
5504                } else {
5505                    last->next = cur;
5506                    last = cur;
5507                }
5508            }
5509        }
5510        nodes = nodes->next;
5511    }
5512    return (def);
5513}
5514
5515/**
5516 * xmlRelaxNGParseStart:
5517 * @ctxt:  a Relax-NG parser context
5518 * @nodes:  start children nodes
5519 *
5520 * parse the content of a RelaxNG start node.
5521 *
5522 * Returns 0 in case of success, -1 in case of error
5523 */
5524static int
5525xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5526{
5527    int ret = 0;
5528    xmlRelaxNGDefinePtr def = NULL, last;
5529
5530    if (nodes == NULL) {
5531        xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5532                   NULL, NULL);
5533        return (-1);
5534    }
5535    if (IS_RELAXNG(nodes, "empty")) {
5536        def = xmlRelaxNGNewDefine(ctxt, nodes);
5537        if (def == NULL)
5538            return (-1);
5539        def->type = XML_RELAXNG_EMPTY;
5540        if (nodes->children != NULL) {
5541            xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5542                       "element empty is not empty\n", NULL, NULL);
5543        }
5544    } else if (IS_RELAXNG(nodes, "notAllowed")) {
5545        def = xmlRelaxNGNewDefine(ctxt, nodes);
5546        if (def == NULL)
5547            return (-1);
5548        def->type = XML_RELAXNG_NOT_ALLOWED;
5549        if (nodes->children != NULL) {
5550            xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5551                       "element notAllowed is not empty\n", NULL, NULL);
5552        }
5553    } else {
5554        def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
5555    }
5556    if (ctxt->grammar->start != NULL) {
5557        last = ctxt->grammar->start;
5558        while (last->next != NULL)
5559            last = last->next;
5560        last->next = def;
5561    } else {
5562        ctxt->grammar->start = def;
5563    }
5564    nodes = nodes->next;
5565    if (nodes != NULL) {
5566        xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5567                   "start more than one children\n", NULL, NULL);
5568        return (-1);
5569    }
5570    return (ret);
5571}
5572
5573/**
5574 * xmlRelaxNGParseGrammarContent:
5575 * @ctxt:  a Relax-NG parser context
5576 * @nodes:  grammar children nodes
5577 *
5578 * parse the content of a RelaxNG grammar node.
5579 *
5580 * Returns 0 in case of success, -1 in case of error
5581 */
5582static int
5583xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5584                              xmlNodePtr nodes)
5585{
5586    int ret = 0, tmp;
5587
5588    if (nodes == NULL) {
5589        xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5590                   "grammar has no children\n", NULL, NULL);
5591        return (-1);
5592    }
5593    while (nodes != NULL) {
5594        if (IS_RELAXNG(nodes, "start")) {
5595            if (nodes->children == NULL) {
5596                xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5597                           "start has no children\n", NULL, NULL);
5598            } else {
5599                tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5600                if (tmp != 0)
5601                    ret = -1;
5602            }
5603        } else if (IS_RELAXNG(nodes, "define")) {
5604            tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5605            if (tmp != 0)
5606                ret = -1;
5607        } else if (IS_RELAXNG(nodes, "include")) {
5608            tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5609            if (tmp != 0)
5610                ret = -1;
5611        } else {
5612            xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5613                       "grammar has unexpected child %s\n", nodes->name,
5614                       NULL);
5615            ret = -1;
5616        }
5617        nodes = nodes->next;
5618    }
5619    return (ret);
5620}
5621
5622/**
5623 * xmlRelaxNGCheckReference:
5624 * @ref:  the ref
5625 * @ctxt:  a Relax-NG parser context
5626 * @name:  the name associated to the defines
5627 *
5628 * Applies the 4.17. combine attribute rule for all the define
5629 * element of a given grammar using the same name.
5630 */
5631static void
5632xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5633                         xmlRelaxNGParserCtxtPtr ctxt,
5634                         const xmlChar * name)
5635{
5636    xmlRelaxNGGrammarPtr grammar;
5637    xmlRelaxNGDefinePtr def, cur;
5638
5639    grammar = ctxt->grammar;
5640    if (grammar == NULL) {
5641        xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5642                   "Internal error: no grammar in CheckReference %s\n",
5643                   name, NULL);
5644        return;
5645    }
5646    if (ref->content != NULL) {
5647        xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5648                   "Internal error: reference has content in CheckReference %s\n",
5649                   name, NULL);
5650        return;
5651    }
5652    if (grammar->defs != NULL) {
5653        def = xmlHashLookup(grammar->defs, name);
5654        if (def != NULL) {
5655            cur = ref;
5656            while (cur != NULL) {
5657                cur->content = def;
5658                cur = cur->nextHash;
5659            }
5660        } else {
5661            xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5662                       "Reference %s has no matching definition\n", name,
5663                       NULL);
5664        }
5665    } else {
5666        xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5667                   "Reference %s has no matching definition\n", name,
5668                   NULL);
5669    }
5670}
5671
5672/**
5673 * xmlRelaxNGCheckCombine:
5674 * @define:  the define(s) list
5675 * @ctxt:  a Relax-NG parser context
5676 * @name:  the name associated to the defines
5677 *
5678 * Applies the 4.17. combine attribute rule for all the define
5679 * element of a given grammar using the same name.
5680 */
5681static void
5682xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5683                       xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5684{
5685    xmlChar *combine;
5686    int choiceOrInterleave = -1;
5687    int missing = 0;
5688    xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5689
5690    if (define->nextHash == NULL)
5691        return;
5692    cur = define;
5693    while (cur != NULL) {
5694        combine = xmlGetProp(cur->node, BAD_CAST "combine");
5695        if (combine != NULL) {
5696            if (xmlStrEqual(combine, BAD_CAST "choice")) {
5697                if (choiceOrInterleave == -1)
5698                    choiceOrInterleave = 1;
5699                else if (choiceOrInterleave == 0) {
5700                    xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5701                               "Defines for %s use both 'choice' and 'interleave'\n",
5702                               name, NULL);
5703                }
5704            } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5705                if (choiceOrInterleave == -1)
5706                    choiceOrInterleave = 0;
5707                else if (choiceOrInterleave == 1) {
5708                    xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5709                               "Defines for %s use both 'choice' and 'interleave'\n",
5710                               name, NULL);
5711                }
5712            } else {
5713                xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5714                           "Defines for %s use unknown combine value '%s''\n",
5715                           name, combine);
5716            }
5717            xmlFree(combine);
5718        } else {
5719            if (missing == 0)
5720                missing = 1;
5721            else {
5722                xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5723                           "Some defines for %s needs the combine attribute\n",
5724                           name, NULL);
5725            }
5726        }
5727
5728        cur = cur->nextHash;
5729    }
5730#ifdef DEBUG
5731    xmlGenericError(xmlGenericErrorContext,
5732                    "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5733                    name, choiceOrInterleave);
5734#endif
5735    if (choiceOrInterleave == -1)
5736        choiceOrInterleave = 0;
5737    cur = xmlRelaxNGNewDefine(ctxt, define->node);
5738    if (cur == NULL)
5739        return;
5740    if (choiceOrInterleave == 0)
5741        cur->type = XML_RELAXNG_INTERLEAVE;
5742    else
5743        cur->type = XML_RELAXNG_CHOICE;
5744    tmp = define;
5745    last = NULL;
5746    while (tmp != NULL) {
5747        if (tmp->content != NULL) {
5748            if (tmp->content->next != NULL) {
5749                /*
5750                 * we need first to create a wrapper.
5751                 */
5752                tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5753                if (tmp2 == NULL)
5754                    break;
5755                tmp2->type = XML_RELAXNG_GROUP;
5756                tmp2->content = tmp->content;
5757            } else {
5758                tmp2 = tmp->content;
5759            }
5760            if (last == NULL) {
5761                cur->content = tmp2;
5762            } else {
5763                last->next = tmp2;
5764            }
5765            last = tmp2;
5766        }
5767        tmp->content = cur;
5768        tmp = tmp->nextHash;
5769    }
5770    define->content = cur;
5771    if (choiceOrInterleave == 0) {
5772        if (ctxt->interleaves == NULL)
5773            ctxt->interleaves = xmlHashCreate(10);
5774        if (ctxt->interleaves == NULL) {
5775            xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5776                       "Failed to create interleaves hash table\n", NULL,
5777                       NULL);
5778        } else {
5779            char tmpname[32];
5780
5781            snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5782            if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5783                0) {
5784                xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5785                           "Failed to add %s to hash table\n",
5786			   (const xmlChar *) tmpname, NULL);
5787            }
5788        }
5789    }
5790}
5791
5792/**
5793 * xmlRelaxNGCombineStart:
5794 * @ctxt:  a Relax-NG parser context
5795 * @grammar:  the grammar
5796 *
5797 * Applies the 4.17. combine rule for all the start
5798 * element of a given grammar.
5799 */
5800static void
5801xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5802                       xmlRelaxNGGrammarPtr grammar)
5803{
5804    xmlRelaxNGDefinePtr starts;
5805    xmlChar *combine;
5806    int choiceOrInterleave = -1;
5807    int missing = 0;
5808    xmlRelaxNGDefinePtr cur;
5809
5810    starts = grammar->start;
5811    if ((starts == NULL) || (starts->next == NULL))
5812        return;
5813    cur = starts;
5814    while (cur != NULL) {
5815        if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5816            (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5817            combine = NULL;
5818            xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5819                       "Internal error: start element not found\n", NULL,
5820                       NULL);
5821        } else {
5822            combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5823        }
5824
5825        if (combine != NULL) {
5826            if (xmlStrEqual(combine, BAD_CAST "choice")) {
5827                if (choiceOrInterleave == -1)
5828                    choiceOrInterleave = 1;
5829                else if (choiceOrInterleave == 0) {
5830                    xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5831                               "<start> use both 'choice' and 'interleave'\n",
5832                               NULL, NULL);
5833                }
5834            } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5835                if (choiceOrInterleave == -1)
5836                    choiceOrInterleave = 0;
5837                else if (choiceOrInterleave == 1) {
5838                    xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5839                               "<start> use both 'choice' and 'interleave'\n",
5840                               NULL, NULL);
5841                }
5842            } else {
5843                xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5844                           "<start> uses unknown combine value '%s''\n",
5845                           combine, NULL);
5846            }
5847            xmlFree(combine);
5848        } else {
5849            if (missing == 0)
5850                missing = 1;
5851            else {
5852                xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5853                           "Some <start> element miss the combine attribute\n",
5854                           NULL, NULL);
5855            }
5856        }
5857
5858        cur = cur->next;
5859    }
5860#ifdef DEBUG
5861    xmlGenericError(xmlGenericErrorContext,
5862                    "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5863                    choiceOrInterleave);
5864#endif
5865    if (choiceOrInterleave == -1)
5866        choiceOrInterleave = 0;
5867    cur = xmlRelaxNGNewDefine(ctxt, starts->node);
5868    if (cur == NULL)
5869        return;
5870    if (choiceOrInterleave == 0)
5871        cur->type = XML_RELAXNG_INTERLEAVE;
5872    else
5873        cur->type = XML_RELAXNG_CHOICE;
5874    cur->content = grammar->start;
5875    grammar->start = cur;
5876    if (choiceOrInterleave == 0) {
5877        if (ctxt->interleaves == NULL)
5878            ctxt->interleaves = xmlHashCreate(10);
5879        if (ctxt->interleaves == NULL) {
5880            xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5881                       "Failed to create interleaves hash table\n", NULL,
5882                       NULL);
5883        } else {
5884            char tmpname[32];
5885
5886            snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5887            if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5888                0) {
5889                xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5890                           "Failed to add %s to hash table\n",
5891			   (const xmlChar *) tmpname, NULL);
5892            }
5893        }
5894    }
5895}
5896
5897/**
5898 * xmlRelaxNGCheckCycles:
5899 * @ctxt:  a Relax-NG parser context
5900 * @nodes:  grammar children nodes
5901 * @depth:  the counter
5902 *
5903 * Check for cycles.
5904 *
5905 * Returns 0 if check passed, and -1 in case of error
5906 */
5907static int
5908xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5909                      xmlRelaxNGDefinePtr cur, int depth)
5910{
5911    int ret = 0;
5912
5913    while ((ret == 0) && (cur != NULL)) {
5914        if ((cur->type == XML_RELAXNG_REF) ||
5915            (cur->type == XML_RELAXNG_PARENTREF)) {
5916            if (cur->depth == -1) {
5917                cur->depth = depth;
5918                ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5919                cur->depth = -2;
5920            } else if (depth == cur->depth) {
5921                xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5922                           "Detected a cycle in %s references\n",
5923                           cur->name, NULL);
5924                return (-1);
5925            }
5926        } else if (cur->type == XML_RELAXNG_ELEMENT) {
5927            ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5928        } else {
5929            ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5930        }
5931        cur = cur->next;
5932    }
5933    return (ret);
5934}
5935
5936/**
5937 * xmlRelaxNGTryUnlink:
5938 * @ctxt:  a Relax-NG parser context
5939 * @cur:  the definition to unlink
5940 * @parent:  the parent definition
5941 * @prev:  the previous sibling definition
5942 *
5943 * Try to unlink a definition. If not possble make it a NOOP
5944 *
5945 * Returns the new prev definition
5946 */
5947static xmlRelaxNGDefinePtr
5948xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5949                    xmlRelaxNGDefinePtr cur,
5950                    xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5951{
5952    if (prev != NULL) {
5953        prev->next = cur->next;
5954    } else {
5955        if (parent != NULL) {
5956            if (parent->content == cur)
5957                parent->content = cur->next;
5958            else if (parent->attrs == cur)
5959                parent->attrs = cur->next;
5960            else if (parent->nameClass == cur)
5961                parent->nameClass = cur->next;
5962        } else {
5963            cur->type = XML_RELAXNG_NOOP;
5964            prev = cur;
5965        }
5966    }
5967    return (prev);
5968}
5969
5970/**
5971 * xmlRelaxNGSimplify:
5972 * @ctxt:  a Relax-NG parser context
5973 * @nodes:  grammar children nodes
5974 *
5975 * Check for simplification of empty and notAllowed
5976 */
5977static void
5978xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5979                   xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5980{
5981    xmlRelaxNGDefinePtr prev = NULL;
5982
5983    while (cur != NULL) {
5984        if ((cur->type == XML_RELAXNG_REF) ||
5985            (cur->type == XML_RELAXNG_PARENTREF)) {
5986            if (cur->depth != -3) {
5987                cur->depth = -3;
5988                xmlRelaxNGSimplify(ctxt, cur->content, cur);
5989            }
5990        } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5991            cur->parent = parent;
5992            if ((parent != NULL) &&
5993                ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5994                 (parent->type == XML_RELAXNG_LIST) ||
5995                 (parent->type == XML_RELAXNG_GROUP) ||
5996                 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5997                 (parent->type == XML_RELAXNG_ONEORMORE) ||
5998                 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5999                parent->type = XML_RELAXNG_NOT_ALLOWED;
6000                break;
6001            }
6002            if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
6003                prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6004            } else
6005                prev = cur;
6006        } else if (cur->type == XML_RELAXNG_EMPTY) {
6007            cur->parent = parent;
6008            if ((parent != NULL) &&
6009                ((parent->type == XML_RELAXNG_ONEORMORE) ||
6010                 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6011                parent->type = XML_RELAXNG_EMPTY;
6012                break;
6013            }
6014            if ((parent != NULL) &&
6015                ((parent->type == XML_RELAXNG_GROUP) ||
6016                 (parent->type == XML_RELAXNG_INTERLEAVE))) {
6017                prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6018            } else
6019                prev = cur;
6020        } else {
6021            cur->parent = parent;
6022            if (cur->content != NULL)
6023                xmlRelaxNGSimplify(ctxt, cur->content, cur);
6024            if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
6025                xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
6026            if (cur->nameClass != NULL)
6027                xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
6028            /*
6029             * On Elements, try to move attribute only generating rules on
6030             * the attrs rules.
6031             */
6032            if (cur->type == XML_RELAXNG_ELEMENT) {
6033                int attronly;
6034                xmlRelaxNGDefinePtr tmp, pre;
6035
6036                while (cur->content != NULL) {
6037                    attronly =
6038                        xmlRelaxNGGenerateAttributes(ctxt, cur->content);
6039                    if (attronly == 1) {
6040                        /*
6041                         * migrate cur->content to attrs
6042                         */
6043                        tmp = cur->content;
6044                        cur->content = tmp->next;
6045                        tmp->next = cur->attrs;
6046                        cur->attrs = tmp;
6047                    } else {
6048                        /*
6049                         * cur->content can generate elements or text
6050                         */
6051                        break;
6052                    }
6053                }
6054                pre = cur->content;
6055                while ((pre != NULL) && (pre->next != NULL)) {
6056                    tmp = pre->next;
6057                    attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
6058                    if (attronly == 1) {
6059                        /*
6060                         * migrate tmp to attrs
6061                         */
6062                        pre->next = tmp->next;
6063                        tmp->next = cur->attrs;
6064                        cur->attrs = tmp;
6065                    } else {
6066                        pre = tmp;
6067                    }
6068                }
6069            }
6070            /*
6071             * This may result in a simplification
6072             */
6073            if ((cur->type == XML_RELAXNG_GROUP) ||
6074                (cur->type == XML_RELAXNG_INTERLEAVE)) {
6075                if (cur->content == NULL)
6076                    cur->type = XML_RELAXNG_EMPTY;
6077                else if (cur->content->next == NULL) {
6078                    if ((parent == NULL) && (prev == NULL)) {
6079                        cur->type = XML_RELAXNG_NOOP;
6080                    } else if (prev == NULL) {
6081                        parent->content = cur->content;
6082                        cur->content->next = cur->next;
6083                        cur = cur->content;
6084                    } else {
6085                        cur->content->next = cur->next;
6086                        prev->next = cur->content;
6087                        cur = cur->content;
6088                    }
6089                }
6090            }
6091            /*
6092             * the current node may have been transformed back
6093             */
6094            if ((cur->type == XML_RELAXNG_EXCEPT) &&
6095                (cur->content != NULL) &&
6096                (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6097                prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6098            } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6099                if ((parent != NULL) &&
6100                    ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6101                     (parent->type == XML_RELAXNG_LIST) ||
6102                     (parent->type == XML_RELAXNG_GROUP) ||
6103                     (parent->type == XML_RELAXNG_INTERLEAVE) ||
6104                     (parent->type == XML_RELAXNG_ONEORMORE) ||
6105                     (parent->type == XML_RELAXNG_ZEROORMORE))) {
6106                    parent->type = XML_RELAXNG_NOT_ALLOWED;
6107                    break;
6108                }
6109                if ((parent != NULL) &&
6110                    (parent->type == XML_RELAXNG_CHOICE)) {
6111                    prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6112                } else
6113                    prev = cur;
6114            } else if (cur->type == XML_RELAXNG_EMPTY) {
6115                if ((parent != NULL) &&
6116                    ((parent->type == XML_RELAXNG_ONEORMORE) ||
6117                     (parent->type == XML_RELAXNG_ZEROORMORE))) {
6118                    parent->type = XML_RELAXNG_EMPTY;
6119                    break;
6120                }
6121                if ((parent != NULL) &&
6122                    ((parent->type == XML_RELAXNG_GROUP) ||
6123                     (parent->type == XML_RELAXNG_INTERLEAVE) ||
6124                     (parent->type == XML_RELAXNG_CHOICE))) {
6125                    prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6126                } else
6127                    prev = cur;
6128            } else {
6129                prev = cur;
6130            }
6131        }
6132        cur = cur->next;
6133    }
6134}
6135
6136/**
6137 * xmlRelaxNGGroupContentType:
6138 * @ct1:  the first content type
6139 * @ct2:  the second content type
6140 *
6141 * Try to group 2 content types
6142 *
6143 * Returns the content type
6144 */
6145static xmlRelaxNGContentType
6146xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6147                           xmlRelaxNGContentType ct2)
6148{
6149    if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6150        (ct2 == XML_RELAXNG_CONTENT_ERROR))
6151        return (XML_RELAXNG_CONTENT_ERROR);
6152    if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6153        return (ct2);
6154    if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6155        return (ct1);
6156    if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6157        (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6158        return (XML_RELAXNG_CONTENT_COMPLEX);
6159    return (XML_RELAXNG_CONTENT_ERROR);
6160}
6161
6162/**
6163 * xmlRelaxNGMaxContentType:
6164 * @ct1:  the first content type
6165 * @ct2:  the second content type
6166 *
6167 * Compute the max content-type
6168 *
6169 * Returns the content type
6170 */
6171static xmlRelaxNGContentType
6172xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6173                         xmlRelaxNGContentType ct2)
6174{
6175    if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6176        (ct2 == XML_RELAXNG_CONTENT_ERROR))
6177        return (XML_RELAXNG_CONTENT_ERROR);
6178    if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6179        (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6180        return (XML_RELAXNG_CONTENT_SIMPLE);
6181    if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6182        (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6183        return (XML_RELAXNG_CONTENT_COMPLEX);
6184    return (XML_RELAXNG_CONTENT_EMPTY);
6185}
6186
6187/**
6188 * xmlRelaxNGCheckRules:
6189 * @ctxt:  a Relax-NG parser context
6190 * @cur:  the current definition
6191 * @flags:  some accumulated flags
6192 * @ptype:  the parent type
6193 *
6194 * Check for rules in section 7.1 and 7.2
6195 *
6196 * Returns the content type of @cur
6197 */
6198static xmlRelaxNGContentType
6199xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6200                     xmlRelaxNGDefinePtr cur, int flags,
6201                     xmlRelaxNGType ptype)
6202{
6203    int nflags = flags;
6204    xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
6205
6206    while (cur != NULL) {
6207        ret = XML_RELAXNG_CONTENT_EMPTY;
6208        if ((cur->type == XML_RELAXNG_REF) ||
6209            (cur->type == XML_RELAXNG_PARENTREF)) {
6210           /*
6211            * This should actually be caught by list//element(ref) at the
6212            * element boundaries, c.f. Bug #159968 local refs are dropped
6213            * in step 4.19.
6214            */
6215#if 0
6216            if (flags & XML_RELAXNG_IN_LIST) {
6217                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6218                           "Found forbidden pattern list//ref\n", NULL,
6219                           NULL);
6220            }
6221#endif
6222            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6223                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6224                           "Found forbidden pattern data/except//ref\n",
6225                           NULL, NULL);
6226            }
6227            if (cur->content == NULL) {
6228                if (cur->type == XML_RELAXNG_PARENTREF)
6229                    xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6230                               "Internal found no define for parent refs\n",
6231                               NULL, NULL);
6232                else
6233                    xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6234                               "Internal found no define for ref %s\n",
6235                               (cur->name ? cur->name: "null"), NULL);
6236            }
6237            if (cur->depth > -4) {
6238                cur->depth = -4;
6239                ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6240                                           flags, cur->type);
6241                cur->depth = ret - 15;
6242            } else if (cur->depth == -4) {
6243                ret = XML_RELAXNG_CONTENT_COMPLEX;
6244            } else {
6245                ret = (xmlRelaxNGContentType) (cur->depth + 15);
6246            }
6247        } else if (cur->type == XML_RELAXNG_ELEMENT) {
6248            /*
6249             * The 7.3 Attribute derivation rule for groups is plugged there
6250             */
6251            xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6252            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6253                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6254                           "Found forbidden pattern data/except//element(ref)\n",
6255                           NULL, NULL);
6256            }
6257            if (flags & XML_RELAXNG_IN_LIST) {
6258                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6259                           "Found forbidden pattern list//element(ref)\n",
6260                           NULL, NULL);
6261            }
6262            if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6263                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6264                           "Found forbidden pattern attribute//element(ref)\n",
6265                           NULL, NULL);
6266            }
6267            if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6268                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6269                           "Found forbidden pattern attribute//element(ref)\n",
6270                           NULL, NULL);
6271            }
6272            /*
6273             * reset since in the simple form elements are only child
6274             * of grammar/define
6275             */
6276            nflags = 0;
6277            ret =
6278                xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6279            if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6280                xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6281                           "Element %s attributes have a content type error\n",
6282                           cur->name, NULL);
6283            }
6284            ret =
6285                xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6286                                     cur->type);
6287            if (ret == XML_RELAXNG_CONTENT_ERROR) {
6288                xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6289                           "Element %s has a content type error\n",
6290                           cur->name, NULL);
6291            } else {
6292                ret = XML_RELAXNG_CONTENT_COMPLEX;
6293            }
6294        } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6295            if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6296                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6297                           "Found forbidden pattern attribute//attribute\n",
6298                           NULL, NULL);
6299            }
6300            if (flags & XML_RELAXNG_IN_LIST) {
6301                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6302                           "Found forbidden pattern list//attribute\n",
6303                           NULL, NULL);
6304            }
6305            if (flags & XML_RELAXNG_IN_OOMGROUP) {
6306                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6307                           "Found forbidden pattern oneOrMore//group//attribute\n",
6308                           NULL, NULL);
6309            }
6310            if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6311                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6312                           "Found forbidden pattern oneOrMore//interleave//attribute\n",
6313                           NULL, NULL);
6314            }
6315            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6316                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6317                           "Found forbidden pattern data/except//attribute\n",
6318                           NULL, NULL);
6319            }
6320            if (flags & XML_RELAXNG_IN_START) {
6321                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6322                           "Found forbidden pattern start//attribute\n",
6323                           NULL, NULL);
6324            }
6325            if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6326                && (cur->name == NULL)) {
6327                if (cur->ns == NULL) {
6328                    xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6329                               "Found anyName attribute without oneOrMore ancestor\n",
6330                               NULL, NULL);
6331                } else {
6332                    xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6333                               "Found nsName attribute without oneOrMore ancestor\n",
6334                               NULL, NULL);
6335                }
6336            }
6337            nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6338            xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6339            ret = XML_RELAXNG_CONTENT_EMPTY;
6340        } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6341                   (cur->type == XML_RELAXNG_ZEROORMORE)) {
6342            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6343                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6344                           "Found forbidden pattern data/except//oneOrMore\n",
6345                           NULL, NULL);
6346            }
6347            if (flags & XML_RELAXNG_IN_START) {
6348                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6349                           "Found forbidden pattern start//oneOrMore\n",
6350                           NULL, NULL);
6351            }
6352            nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6353            ret =
6354                xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6355                                     cur->type);
6356            ret = xmlRelaxNGGroupContentType(ret, ret);
6357        } else if (cur->type == XML_RELAXNG_LIST) {
6358            if (flags & XML_RELAXNG_IN_LIST) {
6359                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6360                           "Found forbidden pattern list//list\n", NULL,
6361                           NULL);
6362            }
6363            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6364                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6365                           "Found forbidden pattern data/except//list\n",
6366                           NULL, NULL);
6367            }
6368            if (flags & XML_RELAXNG_IN_START) {
6369                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6370                           "Found forbidden pattern start//list\n", NULL,
6371                           NULL);
6372            }
6373            nflags = flags | XML_RELAXNG_IN_LIST;
6374            ret =
6375                xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6376                                     cur->type);
6377        } else if (cur->type == XML_RELAXNG_GROUP) {
6378            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6379                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6380                           "Found forbidden pattern data/except//group\n",
6381                           NULL, NULL);
6382            }
6383            if (flags & XML_RELAXNG_IN_START) {
6384                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6385                           "Found forbidden pattern start//group\n", NULL,
6386                           NULL);
6387            }
6388            if (flags & XML_RELAXNG_IN_ONEORMORE)
6389                nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6390            else
6391                nflags = flags;
6392            ret =
6393                xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6394                                     cur->type);
6395            /*
6396             * The 7.3 Attribute derivation rule for groups is plugged there
6397             */
6398            xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6399        } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6400            if (flags & XML_RELAXNG_IN_LIST) {
6401                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6402                           "Found forbidden pattern list//interleave\n",
6403                           NULL, NULL);
6404            }
6405            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6406                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6407                           "Found forbidden pattern data/except//interleave\n",
6408                           NULL, NULL);
6409            }
6410            if (flags & XML_RELAXNG_IN_START) {
6411                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6412                           "Found forbidden pattern start//interleave\n",
6413                           NULL, NULL);
6414            }
6415            if (flags & XML_RELAXNG_IN_ONEORMORE)
6416                nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6417            else
6418                nflags = flags;
6419            ret =
6420                xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6421                                     cur->type);
6422        } else if (cur->type == XML_RELAXNG_EXCEPT) {
6423            if ((cur->parent != NULL) &&
6424                (cur->parent->type == XML_RELAXNG_DATATYPE))
6425                nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6426            else
6427                nflags = flags;
6428            ret =
6429                xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6430                                     cur->type);
6431        } else if (cur->type == XML_RELAXNG_DATATYPE) {
6432            if (flags & XML_RELAXNG_IN_START) {
6433                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6434                           "Found forbidden pattern start//data\n", NULL,
6435                           NULL);
6436            }
6437            xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6438            ret = XML_RELAXNG_CONTENT_SIMPLE;
6439        } else if (cur->type == XML_RELAXNG_VALUE) {
6440            if (flags & XML_RELAXNG_IN_START) {
6441                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6442                           "Found forbidden pattern start//value\n", NULL,
6443                           NULL);
6444            }
6445            xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6446            ret = XML_RELAXNG_CONTENT_SIMPLE;
6447        } else if (cur->type == XML_RELAXNG_TEXT) {
6448            if (flags & XML_RELAXNG_IN_LIST) {
6449                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6450                           "Found forbidden pattern list//text\n", NULL,
6451                           NULL);
6452            }
6453            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6454                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6455                           "Found forbidden pattern data/except//text\n",
6456                           NULL, NULL);
6457            }
6458            if (flags & XML_RELAXNG_IN_START) {
6459                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6460                           "Found forbidden pattern start//text\n", NULL,
6461                           NULL);
6462            }
6463            ret = XML_RELAXNG_CONTENT_COMPLEX;
6464        } else if (cur->type == XML_RELAXNG_EMPTY) {
6465            if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6466                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6467                           "Found forbidden pattern data/except//empty\n",
6468                           NULL, NULL);
6469            }
6470            if (flags & XML_RELAXNG_IN_START) {
6471                xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6472                           "Found forbidden pattern start//empty\n", NULL,
6473                           NULL);
6474            }
6475            ret = XML_RELAXNG_CONTENT_EMPTY;
6476        } else if (cur->type == XML_RELAXNG_CHOICE) {
6477            xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6478            ret =
6479                xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6480        } else {
6481            ret =
6482                xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6483        }
6484        cur = cur->next;
6485        if (ptype == XML_RELAXNG_GROUP) {
6486            val = xmlRelaxNGGroupContentType(val, ret);
6487        } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6488            tmp = xmlRelaxNGGroupContentType(val, ret);
6489            if (tmp != XML_RELAXNG_CONTENT_ERROR)
6490                tmp = xmlRelaxNGMaxContentType(val, ret);
6491        } else if (ptype == XML_RELAXNG_CHOICE) {
6492            val = xmlRelaxNGMaxContentType(val, ret);
6493        } else if (ptype == XML_RELAXNG_LIST) {
6494            val = XML_RELAXNG_CONTENT_SIMPLE;
6495        } else if (ptype == XML_RELAXNG_EXCEPT) {
6496            if (ret == XML_RELAXNG_CONTENT_ERROR)
6497                val = XML_RELAXNG_CONTENT_ERROR;
6498            else
6499                val = XML_RELAXNG_CONTENT_SIMPLE;
6500        } else {
6501            val = xmlRelaxNGGroupContentType(val, ret);
6502        }
6503
6504    }
6505    return (val);
6506}
6507
6508/**
6509 * xmlRelaxNGParseGrammar:
6510 * @ctxt:  a Relax-NG parser context
6511 * @nodes:  grammar children nodes
6512 *
6513 * parse a Relax-NG <grammar> node
6514 *
6515 * Returns the internal xmlRelaxNGGrammarPtr built or
6516 *         NULL in case of error
6517 */
6518static xmlRelaxNGGrammarPtr
6519xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6520{
6521    xmlRelaxNGGrammarPtr ret, tmp, old;
6522
6523#ifdef DEBUG_GRAMMAR
6524    xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6525#endif
6526
6527    ret = xmlRelaxNGNewGrammar(ctxt);
6528    if (ret == NULL)
6529        return (NULL);
6530
6531    /*
6532     * Link the new grammar in the tree
6533     */
6534    ret->parent = ctxt->grammar;
6535    if (ctxt->grammar != NULL) {
6536        tmp = ctxt->grammar->children;
6537        if (tmp == NULL) {
6538            ctxt->grammar->children = ret;
6539        } else {
6540            while (tmp->next != NULL)
6541                tmp = tmp->next;
6542            tmp->next = ret;
6543        }
6544    }
6545
6546    old = ctxt->grammar;
6547    ctxt->grammar = ret;
6548    xmlRelaxNGParseGrammarContent(ctxt, nodes);
6549    ctxt->grammar = ret;
6550    if (ctxt->grammar == NULL) {
6551        xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6552                   "Failed to parse <grammar> content\n", NULL, NULL);
6553    } else if (ctxt->grammar->start == NULL) {
6554        xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6555                   "Element <grammar> has no <start>\n", NULL, NULL);
6556    }
6557
6558    /*
6559     * Apply 4.17 mergingd rules to defines and starts
6560     */
6561    xmlRelaxNGCombineStart(ctxt, ret);
6562    if (ret->defs != NULL) {
6563        xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6564                    ctxt);
6565    }
6566
6567    /*
6568     * link together defines and refs in this grammar
6569     */
6570    if (ret->refs != NULL) {
6571        xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6572                    ctxt);
6573    }
6574
6575
6576    /* @@@@ */
6577
6578    ctxt->grammar = old;
6579    return (ret);
6580}
6581
6582/**
6583 * xmlRelaxNGParseDocument:
6584 * @ctxt:  a Relax-NG parser context
6585 * @node:  the root node of the RelaxNG schema
6586 *
6587 * parse a Relax-NG definition resource and build an internal
6588 * xmlRelaxNG struture which can be used to validate instances.
6589 *
6590 * Returns the internal XML RelaxNG structure built or
6591 *         NULL in case of error
6592 */
6593static xmlRelaxNGPtr
6594xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6595{
6596    xmlRelaxNGPtr schema = NULL;
6597    const xmlChar *olddefine;
6598    xmlRelaxNGGrammarPtr old;
6599
6600    if ((ctxt == NULL) || (node == NULL))
6601        return (NULL);
6602
6603    schema = xmlRelaxNGNewRelaxNG(ctxt);
6604    if (schema == NULL)
6605        return (NULL);
6606
6607    olddefine = ctxt->define;
6608    ctxt->define = NULL;
6609    if (IS_RELAXNG(node, "grammar")) {
6610        schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6611    } else {
6612        xmlRelaxNGGrammarPtr tmp, ret;
6613
6614        schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6615        if (schema->topgrammar == NULL) {
6616            return (schema);
6617        }
6618        /*
6619         * Link the new grammar in the tree
6620         */
6621        ret->parent = ctxt->grammar;
6622        if (ctxt->grammar != NULL) {
6623            tmp = ctxt->grammar->children;
6624            if (tmp == NULL) {
6625                ctxt->grammar->children = ret;
6626            } else {
6627                while (tmp->next != NULL)
6628                    tmp = tmp->next;
6629                tmp->next = ret;
6630            }
6631        }
6632        old = ctxt->grammar;
6633        ctxt->grammar = ret;
6634        xmlRelaxNGParseStart(ctxt, node);
6635        if (old != NULL)
6636            ctxt->grammar = old;
6637    }
6638    ctxt->define = olddefine;
6639    if (schema->topgrammar->start != NULL) {
6640        xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6641        if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6642            xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6643            while ((schema->topgrammar->start != NULL) &&
6644                   (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6645                   (schema->topgrammar->start->next != NULL))
6646                schema->topgrammar->start =
6647                    schema->topgrammar->start->content;
6648            xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6649                                 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6650        }
6651    }
6652#ifdef DEBUG
6653    if (schema == NULL)
6654        xmlGenericError(xmlGenericErrorContext,
6655                        "xmlRelaxNGParseDocument() failed\n");
6656#endif
6657
6658    return (schema);
6659}
6660
6661/************************************************************************
6662 * 									*
6663 * 			Reading RelaxNGs				*
6664 * 									*
6665 ************************************************************************/
6666
6667/**
6668 * xmlRelaxNGNewParserCtxt:
6669 * @URL:  the location of the schema
6670 *
6671 * Create an XML RelaxNGs parse context for that file/resource expected
6672 * to contain an XML RelaxNGs file.
6673 *
6674 * Returns the parser context or NULL in case of error
6675 */
6676xmlRelaxNGParserCtxtPtr
6677xmlRelaxNGNewParserCtxt(const char *URL)
6678{
6679    xmlRelaxNGParserCtxtPtr ret;
6680
6681    if (URL == NULL)
6682        return (NULL);
6683
6684    ret =
6685        (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6686    if (ret == NULL) {
6687        xmlRngPErrMemory(NULL, "building parser\n");
6688        return (NULL);
6689    }
6690    memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6691    ret->URL = xmlStrdup((const xmlChar *) URL);
6692    ret->error = xmlGenericError;
6693    ret->userData = xmlGenericErrorContext;
6694    return (ret);
6695}
6696
6697/**
6698 * xmlRelaxNGNewMemParserCtxt:
6699 * @buffer:  a pointer to a char array containing the schemas
6700 * @size:  the size of the array
6701 *
6702 * Create an XML RelaxNGs parse context for that memory buffer expected
6703 * to contain an XML RelaxNGs file.
6704 *
6705 * Returns the parser context or NULL in case of error
6706 */
6707xmlRelaxNGParserCtxtPtr
6708xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6709{
6710    xmlRelaxNGParserCtxtPtr ret;
6711
6712    if ((buffer == NULL) || (size <= 0))
6713        return (NULL);
6714
6715    ret =
6716        (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6717    if (ret == NULL) {
6718        xmlRngPErrMemory(NULL, "building parser\n");
6719        return (NULL);
6720    }
6721    memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6722    ret->buffer = buffer;
6723    ret->size = size;
6724    ret->error = xmlGenericError;
6725    ret->userData = xmlGenericErrorContext;
6726    return (ret);
6727}
6728
6729/**
6730 * xmlRelaxNGNewDocParserCtxt:
6731 * @doc:  a preparsed document tree
6732 *
6733 * Create an XML RelaxNGs parser context for that document.
6734 * Note: since the process of compiling a RelaxNG schemas modifies the
6735 *       document, the @doc parameter is duplicated internally.
6736 *
6737 * Returns the parser context or NULL in case of error
6738 */
6739xmlRelaxNGParserCtxtPtr
6740xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6741{
6742    xmlRelaxNGParserCtxtPtr ret;
6743    xmlDocPtr copy;
6744
6745    if (doc == NULL)
6746        return (NULL);
6747    copy = xmlCopyDoc(doc, 1);
6748    if (copy == NULL)
6749        return (NULL);
6750
6751    ret =
6752        (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6753    if (ret == NULL) {
6754        xmlRngPErrMemory(NULL, "building parser\n");
6755        return (NULL);
6756    }
6757    memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6758    ret->document = copy;
6759    ret->freedoc = 1;
6760    ret->userData = xmlGenericErrorContext;
6761    return (ret);
6762}
6763
6764/**
6765 * xmlRelaxNGFreeParserCtxt:
6766 * @ctxt:  the schema parser context
6767 *
6768 * Free the resources associated to the schema parser context
6769 */
6770void
6771xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6772{
6773    if (ctxt == NULL)
6774        return;
6775    if (ctxt->URL != NULL)
6776        xmlFree(ctxt->URL);
6777    if (ctxt->doc != NULL)
6778        xmlRelaxNGFreeDocument(ctxt->doc);
6779    if (ctxt->interleaves != NULL)
6780        xmlHashFree(ctxt->interleaves, NULL);
6781    if (ctxt->documents != NULL)
6782        xmlRelaxNGFreeDocumentList(ctxt->documents);
6783    if (ctxt->includes != NULL)
6784        xmlRelaxNGFreeIncludeList(ctxt->includes);
6785    if (ctxt->docTab != NULL)
6786        xmlFree(ctxt->docTab);
6787    if (ctxt->incTab != NULL)
6788        xmlFree(ctxt->incTab);
6789    if (ctxt->defTab != NULL) {
6790        int i;
6791
6792        for (i = 0; i < ctxt->defNr; i++)
6793            xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6794        xmlFree(ctxt->defTab);
6795    }
6796    if ((ctxt->document != NULL) && (ctxt->freedoc))
6797        xmlFreeDoc(ctxt->document);
6798    xmlFree(ctxt);
6799}
6800
6801/**
6802 * xmlRelaxNGNormExtSpace:
6803 * @value:  a value
6804 *
6805 * Removes the leading and ending spaces of the value
6806 * The string is modified "in situ"
6807 */
6808static void
6809xmlRelaxNGNormExtSpace(xmlChar * value)
6810{
6811    xmlChar *start = value;
6812    xmlChar *cur = value;
6813
6814    if (value == NULL)
6815        return;
6816
6817    while (IS_BLANK_CH(*cur))
6818        cur++;
6819    if (cur == start) {
6820        do {
6821            while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6822                cur++;
6823            if (*cur == 0)
6824                return;
6825            start = cur;
6826            while (IS_BLANK_CH(*cur))
6827                cur++;
6828            if (*cur == 0) {
6829                *start = 0;
6830                return;
6831            }
6832        } while (1);
6833    } else {
6834        do {
6835            while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6836                *start++ = *cur++;
6837            if (*cur == 0) {
6838                *start = 0;
6839                return;
6840            }
6841            /* don't try to normalize the inner spaces */
6842            while (IS_BLANK_CH(*cur))
6843                cur++;
6844            if (*cur == 0) {
6845                *start = 0;
6846                return;
6847            }
6848            *start++ = *cur++;
6849        } while (1);
6850    }
6851}
6852
6853/**
6854 * xmlRelaxNGCleanupAttributes:
6855 * @ctxt:  a Relax-NG parser context
6856 * @node:  a Relax-NG node
6857 *
6858 * Check all the attributes on the given node
6859 */
6860static void
6861xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6862{
6863    xmlAttrPtr cur, next;
6864
6865    cur = node->properties;
6866    while (cur != NULL) {
6867        next = cur->next;
6868        if ((cur->ns == NULL) ||
6869            (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6870            if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6871                if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6872                    (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6873                    (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6874                    (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6875                    (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6876                    (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6877                    xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6878                               "Attribute %s is not allowed on %s\n",
6879                               cur->name, node->name);
6880                }
6881            } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6882                if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6883                    (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6884                    xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6885                               "Attribute %s is not allowed on %s\n",
6886                               cur->name, node->name);
6887                }
6888            } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6889                if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6890                    (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6891                    xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6892                               "Attribute %s is not allowed on %s\n",
6893                               cur->name, node->name);
6894                }
6895            } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6896                if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6897                    (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6898                    xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6899                               "Attribute %s is not allowed on %s\n",
6900                               cur->name, node->name);
6901                }
6902            } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6903                xmlChar *val;
6904                xmlURIPtr uri;
6905
6906                val = xmlNodeListGetString(node->doc, cur->children, 1);
6907                if (val != NULL) {
6908                    if (val[0] != 0) {
6909                        uri = xmlParseURI((const char *) val);
6910                        if (uri == NULL) {
6911                            xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6912                                       "Attribute %s contains invalid URI %s\n",
6913                                       cur->name, val);
6914                        } else {
6915                            if (uri->scheme == NULL) {
6916                                xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6917                                           "Attribute %s URI %s is not absolute\n",
6918                                           cur->name, val);
6919                            }
6920                            if (uri->fragment != NULL) {
6921                                xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6922                                           "Attribute %s URI %s has a fragment ID\n",
6923                                           cur->name, val);
6924                            }
6925                            xmlFreeURI(uri);
6926                        }
6927                    }
6928                    xmlFree(val);
6929                }
6930            } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6931                xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6932                           "Unknown attribute %s on %s\n", cur->name,
6933                           node->name);
6934            }
6935        }
6936        cur = next;
6937    }
6938}
6939
6940/**
6941 * xmlRelaxNGCleanupTree:
6942 * @ctxt:  a Relax-NG parser context
6943 * @root:  an xmlNodePtr subtree
6944 *
6945 * Cleanup the subtree from unwanted nodes for parsing, resolve
6946 * Include and externalRef lookups.
6947 */
6948static void
6949xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6950{
6951    xmlNodePtr cur, delete;
6952
6953    delete = NULL;
6954    cur = root;
6955    while (cur != NULL) {
6956        if (delete != NULL) {
6957            xmlUnlinkNode(delete);
6958            xmlFreeNode(delete);
6959            delete = NULL;
6960        }
6961        if (cur->type == XML_ELEMENT_NODE) {
6962            /*
6963             * Simplification 4.1. Annotations
6964             */
6965            if ((cur->ns == NULL) ||
6966                (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6967                if ((cur->parent != NULL) &&
6968                    (cur->parent->type == XML_ELEMENT_NODE) &&
6969                    ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6970                     (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6971                     (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6972                    xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6973                               "element %s doesn't allow foreign elements\n",
6974                               cur->parent->name, NULL);
6975                }
6976                delete = cur;
6977                goto skip_children;
6978            } else {
6979                xmlRelaxNGCleanupAttributes(ctxt, cur);
6980                if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6981                    xmlChar *href, *ns, *base, *URL;
6982                    xmlRelaxNGDocumentPtr docu;
6983                    xmlNodePtr tmp;
6984		    xmlURIPtr uri;
6985
6986                    ns = xmlGetProp(cur, BAD_CAST "ns");
6987                    if (ns == NULL) {
6988                        tmp = cur->parent;
6989                        while ((tmp != NULL) &&
6990                               (tmp->type == XML_ELEMENT_NODE)) {
6991                            ns = xmlGetProp(tmp, BAD_CAST "ns");
6992                            if (ns != NULL)
6993                                break;
6994                            tmp = tmp->parent;
6995                        }
6996                    }
6997                    href = xmlGetProp(cur, BAD_CAST "href");
6998                    if (href == NULL) {
6999                        xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7000                                   "xmlRelaxNGParse: externalRef has no href attribute\n",
7001                                   NULL, NULL);
7002                        if (ns != NULL)
7003                            xmlFree(ns);
7004                        delete = cur;
7005                        goto skip_children;
7006                    }
7007		    uri = xmlParseURI((const char *) href);
7008		    if (uri == NULL) {
7009                        xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7010                                   "Incorrect URI for externalRef %s\n",
7011                                   href, NULL);
7012                        if (ns != NULL)
7013                            xmlFree(ns);
7014                        if (href != NULL)
7015                            xmlFree(href);
7016                        delete = cur;
7017                        goto skip_children;
7018		    }
7019		    if (uri->fragment != NULL) {
7020                        xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7021			       "Fragment forbidden in URI for externalRef %s\n",
7022                                   href, NULL);
7023                        if (ns != NULL)
7024                            xmlFree(ns);
7025		        xmlFreeURI(uri);
7026                        if (href != NULL)
7027                            xmlFree(href);
7028                        delete = cur;
7029                        goto skip_children;
7030		    }
7031		    xmlFreeURI(uri);
7032                    base = xmlNodeGetBase(cur->doc, cur);
7033                    URL = xmlBuildURI(href, base);
7034                    if (URL == NULL) {
7035                        xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7036                                   "Failed to compute URL for externalRef %s\n",
7037                                   href, NULL);
7038                        if (ns != NULL)
7039                            xmlFree(ns);
7040                        if (href != NULL)
7041                            xmlFree(href);
7042                        if (base != NULL)
7043                            xmlFree(base);
7044                        delete = cur;
7045                        goto skip_children;
7046                    }
7047                    if (href != NULL)
7048                        xmlFree(href);
7049                    if (base != NULL)
7050                        xmlFree(base);
7051                    docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
7052                    if (docu == NULL) {
7053                        xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
7054                                   "Failed to load externalRef %s\n", URL,
7055                                   NULL);
7056                        if (ns != NULL)
7057                            xmlFree(ns);
7058                        xmlFree(URL);
7059                        delete = cur;
7060                        goto skip_children;
7061                    }
7062                    if (ns != NULL)
7063                        xmlFree(ns);
7064                    xmlFree(URL);
7065                    cur->psvi = docu;
7066                } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
7067                    xmlChar *href, *ns, *base, *URL;
7068                    xmlRelaxNGIncludePtr incl;
7069                    xmlNodePtr tmp;
7070
7071                    href = xmlGetProp(cur, BAD_CAST "href");
7072                    if (href == NULL) {
7073                        xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7074                                   "xmlRelaxNGParse: include has no href attribute\n",
7075                                   NULL, NULL);
7076                        delete = cur;
7077                        goto skip_children;
7078                    }
7079                    base = xmlNodeGetBase(cur->doc, cur);
7080                    URL = xmlBuildURI(href, base);
7081                    if (URL == NULL) {
7082                        xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7083                                   "Failed to compute URL for include %s\n",
7084                                   href, NULL);
7085                        if (href != NULL)
7086                            xmlFree(href);
7087                        if (base != NULL)
7088                            xmlFree(base);
7089                        delete = cur;
7090                        goto skip_children;
7091                    }
7092                    if (href != NULL)
7093                        xmlFree(href);
7094                    if (base != NULL)
7095                        xmlFree(base);
7096                    ns = xmlGetProp(cur, BAD_CAST "ns");
7097                    if (ns == NULL) {
7098                        tmp = cur->parent;
7099                        while ((tmp != NULL) &&
7100                               (tmp->type == XML_ELEMENT_NODE)) {
7101                            ns = xmlGetProp(tmp, BAD_CAST "ns");
7102                            if (ns != NULL)
7103                                break;
7104                            tmp = tmp->parent;
7105                        }
7106                    }
7107                    incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7108                    if (ns != NULL)
7109                        xmlFree(ns);
7110                    if (incl == NULL) {
7111                        xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7112                                   "Failed to load include %s\n", URL,
7113                                   NULL);
7114                        xmlFree(URL);
7115                        delete = cur;
7116                        goto skip_children;
7117                    }
7118                    xmlFree(URL);
7119                    cur->psvi = incl;
7120                } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7121                           (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7122                {
7123                    xmlChar *name, *ns;
7124                    xmlNodePtr text = NULL;
7125
7126                    /*
7127                     * Simplification 4.8. name attribute of element
7128                     * and attribute elements
7129                     */
7130                    name = xmlGetProp(cur, BAD_CAST "name");
7131                    if (name != NULL) {
7132                        if (cur->children == NULL) {
7133                            text =
7134                                xmlNewChild(cur, cur->ns, BAD_CAST "name",
7135                                            name);
7136                        } else {
7137                            xmlNodePtr node;
7138
7139                            node = xmlNewDocNode(cur->doc, cur->ns,
7140			                         BAD_CAST "name", NULL);
7141                            if (node != NULL) {
7142                                xmlAddPrevSibling(cur->children, node);
7143                                text = xmlNewText(name);
7144                                xmlAddChild(node, text);
7145                                text = node;
7146                            }
7147                        }
7148                        if (text == NULL) {
7149                            xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7150                                       "Failed to create a name %s element\n",
7151                                       name, NULL);
7152                        }
7153                        xmlUnsetProp(cur, BAD_CAST "name");
7154                        xmlFree(name);
7155                        ns = xmlGetProp(cur, BAD_CAST "ns");
7156                        if (ns != NULL) {
7157                            if (text != NULL) {
7158                                xmlSetProp(text, BAD_CAST "ns", ns);
7159                                /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7160                            }
7161                            xmlFree(ns);
7162                        } else if (xmlStrEqual(cur->name,
7163                                               BAD_CAST "attribute")) {
7164                            xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7165                        }
7166                    }
7167                } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7168                           (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7169                           (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7170                    /*
7171                     * Simplification 4.8. name attribute of element
7172                     * and attribute elements
7173                     */
7174                    if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7175                        xmlNodePtr node;
7176                        xmlChar *ns = NULL;
7177
7178                        node = cur->parent;
7179                        while ((node != NULL) &&
7180                               (node->type == XML_ELEMENT_NODE)) {
7181                            ns = xmlGetProp(node, BAD_CAST "ns");
7182                            if (ns != NULL) {
7183                                break;
7184                            }
7185                            node = node->parent;
7186                        }
7187                        if (ns == NULL) {
7188                            xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7189                        } else {
7190                            xmlSetProp(cur, BAD_CAST "ns", ns);
7191                            xmlFree(ns);
7192                        }
7193                    }
7194                    if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7195                        xmlChar *name, *local, *prefix;
7196
7197                        /*
7198                         * Simplification: 4.10. QNames
7199                         */
7200                        name = xmlNodeGetContent(cur);
7201                        if (name != NULL) {
7202                            local = xmlSplitQName2(name, &prefix);
7203                            if (local != NULL) {
7204                                xmlNsPtr ns;
7205
7206                                ns = xmlSearchNs(cur->doc, cur, prefix);
7207                                if (ns == NULL) {
7208                                    xmlRngPErr(ctxt, cur,
7209                                               XML_RNGP_PREFIX_UNDEFINED,
7210                                               "xmlRelaxNGParse: no namespace for prefix %s\n",
7211                                               prefix, NULL);
7212                                } else {
7213                                    xmlSetProp(cur, BAD_CAST "ns",
7214                                               ns->href);
7215                                    xmlNodeSetContent(cur, local);
7216                                }
7217                                xmlFree(local);
7218                                xmlFree(prefix);
7219                            }
7220                            xmlFree(name);
7221                        }
7222                    }
7223                    /*
7224                     * 4.16
7225                     */
7226                    if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7227                        if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7228                            xmlRngPErr(ctxt, cur,
7229                                       XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7230                                       "Found nsName/except//nsName forbidden construct\n",
7231                                       NULL, NULL);
7232                        }
7233                    }
7234                } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7235                           (cur != root)) {
7236                    int oldflags = ctxt->flags;
7237
7238                    /*
7239                     * 4.16
7240                     */
7241                    if ((cur->parent != NULL) &&
7242                        (xmlStrEqual
7243                         (cur->parent->name, BAD_CAST "anyName"))) {
7244                        ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7245                        xmlRelaxNGCleanupTree(ctxt, cur);
7246                        ctxt->flags = oldflags;
7247                        goto skip_children;
7248                    } else if ((cur->parent != NULL) &&
7249                               (xmlStrEqual
7250                                (cur->parent->name, BAD_CAST "nsName"))) {
7251                        ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7252                        xmlRelaxNGCleanupTree(ctxt, cur);
7253                        ctxt->flags = oldflags;
7254                        goto skip_children;
7255                    }
7256                } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7257                    /*
7258                     * 4.16
7259                     */
7260                    if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7261                        xmlRngPErr(ctxt, cur,
7262                                   XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7263                                   "Found anyName/except//anyName forbidden construct\n",
7264                                   NULL, NULL);
7265                    } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7266                        xmlRngPErr(ctxt, cur,
7267                                   XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7268                                   "Found nsName/except//anyName forbidden construct\n",
7269                                   NULL, NULL);
7270                    }
7271                }
7272                /*
7273                 * Thisd is not an else since "include" is transformed
7274                 * into a div
7275                 */
7276                if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7277                    xmlChar *ns;
7278                    xmlNodePtr child, ins, tmp;
7279
7280                    /*
7281                     * implements rule 4.11
7282                     */
7283
7284                    ns = xmlGetProp(cur, BAD_CAST "ns");
7285
7286                    child = cur->children;
7287                    ins = cur;
7288                    while (child != NULL) {
7289                        if (ns != NULL) {
7290                            if (!xmlHasProp(child, BAD_CAST "ns")) {
7291                                xmlSetProp(child, BAD_CAST "ns", ns);
7292                            }
7293                        }
7294                        tmp = child->next;
7295                        xmlUnlinkNode(child);
7296                        ins = xmlAddNextSibling(ins, child);
7297                        child = tmp;
7298                    }
7299                    if (ns != NULL)
7300                        xmlFree(ns);
7301		    /*
7302		     * Since we are about to delete cur, if it's nsDef is non-NULL we
7303		     * need to preserve it (it contains the ns definitions for the
7304		     * children we just moved).  We'll just stick it on to the end
7305		     * of cur->parent's list, since it's never going to be re-serialized
7306		     * (bug 143738).
7307		     */
7308		    if (cur->nsDef != NULL) {
7309			xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7310			while (parDef->next != NULL)
7311			    parDef = parDef->next;
7312			parDef->next = cur->nsDef;
7313			cur->nsDef = NULL;
7314		    }
7315                    delete = cur;
7316                    goto skip_children;
7317                }
7318            }
7319        }
7320        /*
7321         * Simplification 4.2 whitespaces
7322         */
7323        else if ((cur->type == XML_TEXT_NODE) ||
7324                 (cur->type == XML_CDATA_SECTION_NODE)) {
7325            if (IS_BLANK_NODE(cur)) {
7326                if (cur->parent->type == XML_ELEMENT_NODE) {
7327                    if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7328                        &&
7329                        (!xmlStrEqual
7330                         (cur->parent->name, BAD_CAST "param")))
7331                        delete = cur;
7332                } else {
7333                    delete = cur;
7334                    goto skip_children;
7335                }
7336            }
7337        } else {
7338            delete = cur;
7339            goto skip_children;
7340        }
7341
7342        /*
7343         * Skip to next node
7344         */
7345        if (cur->children != NULL) {
7346            if ((cur->children->type != XML_ENTITY_DECL) &&
7347                (cur->children->type != XML_ENTITY_REF_NODE) &&
7348                (cur->children->type != XML_ENTITY_NODE)) {
7349                cur = cur->children;
7350                continue;
7351            }
7352        }
7353      skip_children:
7354        if (cur->next != NULL) {
7355            cur = cur->next;
7356            continue;
7357        }
7358
7359        do {
7360            cur = cur->parent;
7361            if (cur == NULL)
7362                break;
7363            if (cur == root) {
7364                cur = NULL;
7365                break;
7366            }
7367            if (cur->next != NULL) {
7368                cur = cur->next;
7369                break;
7370            }
7371        } while (cur != NULL);
7372    }
7373    if (delete != NULL) {
7374        xmlUnlinkNode(delete);
7375        xmlFreeNode(delete);
7376        delete = NULL;
7377    }
7378}
7379
7380/**
7381 * xmlRelaxNGCleanupDoc:
7382 * @ctxt:  a Relax-NG parser context
7383 * @doc:  an xmldocPtr document pointer
7384 *
7385 * Cleanup the document from unwanted nodes for parsing, resolve
7386 * Include and externalRef lookups.
7387 *
7388 * Returns the cleaned up document or NULL in case of error
7389 */
7390static xmlDocPtr
7391xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7392{
7393    xmlNodePtr root;
7394
7395    /*
7396     * Extract the root
7397     */
7398    root = xmlDocGetRootElement(doc);
7399    if (root == NULL) {
7400        xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7401                   ctxt->URL, NULL);
7402        return (NULL);
7403    }
7404    xmlRelaxNGCleanupTree(ctxt, root);
7405    return (doc);
7406}
7407
7408/**
7409 * xmlRelaxNGParse:
7410 * @ctxt:  a Relax-NG parser context
7411 *
7412 * parse a schema definition resource and build an internal
7413 * XML Shema struture which can be used to validate instances.
7414 *
7415 * Returns the internal XML RelaxNG structure built from the resource or
7416 *         NULL in case of error
7417 */
7418xmlRelaxNGPtr
7419xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7420{
7421    xmlRelaxNGPtr ret = NULL;
7422    xmlDocPtr doc;
7423    xmlNodePtr root;
7424
7425    xmlRelaxNGInitTypes();
7426
7427    if (ctxt == NULL)
7428        return (NULL);
7429
7430    /*
7431     * First step is to parse the input document into an DOM/Infoset
7432     */
7433    if (ctxt->URL != NULL) {
7434        doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
7435        if (doc == NULL) {
7436            xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7437                       "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7438                       NULL);
7439            return (NULL);
7440        }
7441    } else if (ctxt->buffer != NULL) {
7442        doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
7443        if (doc == NULL) {
7444            xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7445                       "xmlRelaxNGParse: could not parse schemas\n", NULL,
7446                       NULL);
7447            return (NULL);
7448        }
7449        doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7450        ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7451    } else if (ctxt->document != NULL) {
7452        doc = ctxt->document;
7453    } else {
7454        xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7455                   "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7456        return (NULL);
7457    }
7458    ctxt->document = doc;
7459
7460    /*
7461     * Some preprocessing of the document content
7462     */
7463    doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7464    if (doc == NULL) {
7465        xmlFreeDoc(ctxt->document);
7466        ctxt->document = NULL;
7467        return (NULL);
7468    }
7469
7470    /*
7471     * Then do the parsing for good
7472     */
7473    root = xmlDocGetRootElement(doc);
7474    if (root == NULL) {
7475        xmlRngPErr(ctxt, (xmlNodePtr) doc,
7476	           XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7477                   (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
7478
7479        xmlFreeDoc(ctxt->document);
7480        ctxt->document = NULL;
7481        return (NULL);
7482    }
7483    ret = xmlRelaxNGParseDocument(ctxt, root);
7484    if (ret == NULL) {
7485        xmlFreeDoc(ctxt->document);
7486        ctxt->document = NULL;
7487        return (NULL);
7488    }
7489
7490    /*
7491     * Check the ref/defines links
7492     */
7493    /*
7494     * try to preprocess interleaves
7495     */
7496    if (ctxt->interleaves != NULL) {
7497        xmlHashScan(ctxt->interleaves,
7498                    (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
7499    }
7500
7501    /*
7502     * if there was a parsing error return NULL
7503     */
7504    if (ctxt->nbErrors > 0) {
7505        xmlRelaxNGFree(ret);
7506        ctxt->document = NULL;
7507        xmlFreeDoc(doc);
7508        return (NULL);
7509    }
7510
7511    /*
7512     * try to compile (parts of) the schemas
7513     */
7514    if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7515        if (ret->topgrammar->start->type != XML_RELAXNG_START) {
7516            xmlRelaxNGDefinePtr def;
7517
7518            def = xmlRelaxNGNewDefine(ctxt, NULL);
7519            if (def != NULL) {
7520                def->type = XML_RELAXNG_START;
7521                def->content = ret->topgrammar->start;
7522                ret->topgrammar->start = def;
7523            }
7524        }
7525        xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
7526    }
7527
7528    /*
7529     * Transfer the pointer for cleanup at the schema level.
7530     */
7531    ret->doc = doc;
7532    ctxt->document = NULL;
7533    ret->documents = ctxt->documents;
7534    ctxt->documents = NULL;
7535
7536    ret->includes = ctxt->includes;
7537    ctxt->includes = NULL;
7538    ret->defNr = ctxt->defNr;
7539    ret->defTab = ctxt->defTab;
7540    ctxt->defTab = NULL;
7541    if (ctxt->idref == 1)
7542        ret->idref = 1;
7543
7544    return (ret);
7545}
7546
7547/**
7548 * xmlRelaxNGSetParserErrors:
7549 * @ctxt:  a Relax-NG validation context
7550 * @err:  the error callback
7551 * @warn:  the warning callback
7552 * @ctx:  contextual data for the callbacks
7553 *
7554 * Set the callback functions used to handle errors for a validation context
7555 */
7556void
7557xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7558                          xmlRelaxNGValidityErrorFunc err,
7559                          xmlRelaxNGValidityWarningFunc warn, void *ctx)
7560{
7561    if (ctxt == NULL)
7562        return;
7563    ctxt->error = err;
7564    ctxt->warning = warn;
7565    ctxt->serror = NULL;
7566    ctxt->userData = ctx;
7567}
7568
7569/**
7570 * xmlRelaxNGGetParserErrors:
7571 * @ctxt:  a Relax-NG validation context
7572 * @err:  the error callback result
7573 * @warn:  the warning callback result
7574 * @ctx:  contextual data for the callbacks result
7575 *
7576 * Get the callback information used to handle errors for a validation context
7577 *
7578 * Returns -1 in case of failure, 0 otherwise.
7579 */
7580int
7581xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7582                          xmlRelaxNGValidityErrorFunc * err,
7583                          xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7584{
7585    if (ctxt == NULL)
7586        return (-1);
7587    if (err != NULL)
7588        *err = ctxt->error;
7589    if (warn != NULL)
7590        *warn = ctxt->warning;
7591    if (ctx != NULL)
7592        *ctx = ctxt->userData;
7593    return (0);
7594}
7595
7596/**
7597 * xmlRelaxNGSetParserStructuredErrors:
7598 * @ctxt:  a Relax-NG parser context
7599 * @serror:  the error callback
7600 * @ctx:  contextual data for the callbacks
7601 *
7602 * Set the callback functions used to handle errors for a parsing context
7603 */
7604void
7605xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
7606				    xmlStructuredErrorFunc serror,
7607				    void *ctx)
7608{
7609    if (ctxt == NULL)
7610        return;
7611    ctxt->serror = serror;
7612    ctxt->error = NULL;
7613    ctxt->warning = NULL;
7614    ctxt->userData = ctx;
7615}
7616
7617#ifdef LIBXML_OUTPUT_ENABLED
7618
7619/************************************************************************
7620 * 									*
7621 * 			Dump back a compiled form			*
7622 * 									*
7623 ************************************************************************/
7624static void xmlRelaxNGDumpDefine(FILE * output,
7625                                 xmlRelaxNGDefinePtr define);
7626
7627/**
7628 * xmlRelaxNGDumpDefines:
7629 * @output:  the file output
7630 * @defines:  a list of define structures
7631 *
7632 * Dump a RelaxNG structure back
7633 */
7634static void
7635xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7636{
7637    while (defines != NULL) {
7638        xmlRelaxNGDumpDefine(output, defines);
7639        defines = defines->next;
7640    }
7641}
7642
7643/**
7644 * xmlRelaxNGDumpDefine:
7645 * @output:  the file output
7646 * @define:  a define structure
7647 *
7648 * Dump a RelaxNG structure back
7649 */
7650static void
7651xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7652{
7653    if (define == NULL)
7654        return;
7655    switch (define->type) {
7656        case XML_RELAXNG_EMPTY:
7657            fprintf(output, "<empty/>\n");
7658            break;
7659        case XML_RELAXNG_NOT_ALLOWED:
7660            fprintf(output, "<notAllowed/>\n");
7661            break;
7662        case XML_RELAXNG_TEXT:
7663            fprintf(output, "<text/>\n");
7664            break;
7665        case XML_RELAXNG_ELEMENT:
7666            fprintf(output, "<element>\n");
7667            if (define->name != NULL) {
7668                fprintf(output, "<name");
7669                if (define->ns != NULL)
7670                    fprintf(output, " ns=\"%s\"", define->ns);
7671                fprintf(output, ">%s</name>\n", define->name);
7672            }
7673            xmlRelaxNGDumpDefines(output, define->attrs);
7674            xmlRelaxNGDumpDefines(output, define->content);
7675            fprintf(output, "</element>\n");
7676            break;
7677        case XML_RELAXNG_LIST:
7678            fprintf(output, "<list>\n");
7679            xmlRelaxNGDumpDefines(output, define->content);
7680            fprintf(output, "</list>\n");
7681            break;
7682        case XML_RELAXNG_ONEORMORE:
7683            fprintf(output, "<oneOrMore>\n");
7684            xmlRelaxNGDumpDefines(output, define->content);
7685            fprintf(output, "</oneOrMore>\n");
7686            break;
7687        case XML_RELAXNG_ZEROORMORE:
7688            fprintf(output, "<zeroOrMore>\n");
7689            xmlRelaxNGDumpDefines(output, define->content);
7690            fprintf(output, "</zeroOrMore>\n");
7691            break;
7692        case XML_RELAXNG_CHOICE:
7693            fprintf(output, "<choice>\n");
7694            xmlRelaxNGDumpDefines(output, define->content);
7695            fprintf(output, "</choice>\n");
7696            break;
7697        case XML_RELAXNG_GROUP:
7698            fprintf(output, "<group>\n");
7699            xmlRelaxNGDumpDefines(output, define->content);
7700            fprintf(output, "</group>\n");
7701            break;
7702        case XML_RELAXNG_INTERLEAVE:
7703            fprintf(output, "<interleave>\n");
7704            xmlRelaxNGDumpDefines(output, define->content);
7705            fprintf(output, "</interleave>\n");
7706            break;
7707        case XML_RELAXNG_OPTIONAL:
7708            fprintf(output, "<optional>\n");
7709            xmlRelaxNGDumpDefines(output, define->content);
7710            fprintf(output, "</optional>\n");
7711            break;
7712        case XML_RELAXNG_ATTRIBUTE:
7713            fprintf(output, "<attribute>\n");
7714            xmlRelaxNGDumpDefines(output, define->content);
7715            fprintf(output, "</attribute>\n");
7716            break;
7717        case XML_RELAXNG_DEF:
7718            fprintf(output, "<define");
7719            if (define->name != NULL)
7720                fprintf(output, " name=\"%s\"", define->name);
7721            fprintf(output, ">\n");
7722            xmlRelaxNGDumpDefines(output, define->content);
7723            fprintf(output, "</define>\n");
7724            break;
7725        case XML_RELAXNG_REF:
7726            fprintf(output, "<ref");
7727            if (define->name != NULL)
7728                fprintf(output, " name=\"%s\"", define->name);
7729            fprintf(output, ">\n");
7730            xmlRelaxNGDumpDefines(output, define->content);
7731            fprintf(output, "</ref>\n");
7732            break;
7733        case XML_RELAXNG_PARENTREF:
7734            fprintf(output, "<parentRef");
7735            if (define->name != NULL)
7736                fprintf(output, " name=\"%s\"", define->name);
7737            fprintf(output, ">\n");
7738            xmlRelaxNGDumpDefines(output, define->content);
7739            fprintf(output, "</parentRef>\n");
7740            break;
7741        case XML_RELAXNG_EXTERNALREF:
7742            fprintf(output, "<externalRef>");
7743            xmlRelaxNGDumpDefines(output, define->content);
7744            fprintf(output, "</externalRef>\n");
7745            break;
7746        case XML_RELAXNG_DATATYPE:
7747        case XML_RELAXNG_VALUE:
7748            TODO break;
7749        case XML_RELAXNG_START:
7750        case XML_RELAXNG_EXCEPT:
7751        case XML_RELAXNG_PARAM:
7752            TODO break;
7753        case XML_RELAXNG_NOOP:
7754            xmlRelaxNGDumpDefines(output, define->content);
7755            break;
7756    }
7757}
7758
7759/**
7760 * xmlRelaxNGDumpGrammar:
7761 * @output:  the file output
7762 * @grammar:  a grammar structure
7763 * @top:  is this a top grammar
7764 *
7765 * Dump a RelaxNG structure back
7766 */
7767static void
7768xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7769{
7770    if (grammar == NULL)
7771        return;
7772
7773    fprintf(output, "<grammar");
7774    if (top)
7775        fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7776    switch (grammar->combine) {
7777        case XML_RELAXNG_COMBINE_UNDEFINED:
7778            break;
7779        case XML_RELAXNG_COMBINE_CHOICE:
7780            fprintf(output, " combine=\"choice\"");
7781            break;
7782        case XML_RELAXNG_COMBINE_INTERLEAVE:
7783            fprintf(output, " combine=\"interleave\"");
7784            break;
7785        default:
7786            fprintf(output, " <!-- invalid combine value -->");
7787    }
7788    fprintf(output, ">\n");
7789    if (grammar->start == NULL) {
7790        fprintf(output, " <!-- grammar had no start -->");
7791    } else {
7792        fprintf(output, "<start>\n");
7793        xmlRelaxNGDumpDefine(output, grammar->start);
7794        fprintf(output, "</start>\n");
7795    }
7796    /* TODO ? Dump the defines ? */
7797    fprintf(output, "</grammar>\n");
7798}
7799
7800/**
7801 * xmlRelaxNGDump:
7802 * @output:  the file output
7803 * @schema:  a schema structure
7804 *
7805 * Dump a RelaxNG structure back
7806 */
7807void
7808xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7809{
7810    if (output == NULL)
7811        return;
7812    if (schema == NULL) {
7813        fprintf(output, "RelaxNG empty or failed to compile\n");
7814        return;
7815    }
7816    fprintf(output, "RelaxNG: ");
7817    if (schema->doc == NULL) {
7818        fprintf(output, "no document\n");
7819    } else if (schema->doc->URL != NULL) {
7820        fprintf(output, "%s\n", schema->doc->URL);
7821    } else {
7822        fprintf(output, "\n");
7823    }
7824    if (schema->topgrammar == NULL) {
7825        fprintf(output, "RelaxNG has no top grammar\n");
7826        return;
7827    }
7828    xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7829}
7830
7831/**
7832 * xmlRelaxNGDumpTree:
7833 * @output:  the file output
7834 * @schema:  a schema structure
7835 *
7836 * Dump the transformed RelaxNG tree.
7837 */
7838void
7839xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7840{
7841    if (output == NULL)
7842        return;
7843    if (schema == NULL) {
7844        fprintf(output, "RelaxNG empty or failed to compile\n");
7845        return;
7846    }
7847    if (schema->doc == NULL) {
7848        fprintf(output, "no document\n");
7849    } else {
7850        xmlDocDump(output, schema->doc);
7851    }
7852}
7853#endif /* LIBXML_OUTPUT_ENABLED */
7854
7855/************************************************************************
7856 * 									*
7857 * 		Validation of compiled content				*
7858 * 									*
7859 ************************************************************************/
7860static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7861                                        xmlRelaxNGDefinePtr define);
7862
7863/**
7864 * xmlRelaxNGValidateCompiledCallback:
7865 * @exec:  the regular expression instance
7866 * @token:  the token which matched
7867 * @transdata:  callback data, the define for the subelement if available
7868 @ @inputdata:  callback data, the Relax NG validation context
7869 *
7870 * Handle the callback and if needed validate the element children.
7871 */
7872static void
7873xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7874                                   const xmlChar * token,
7875                                   void *transdata, void *inputdata)
7876{
7877    xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7878    xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7879    int ret;
7880
7881#ifdef DEBUG_COMPILE
7882    xmlGenericError(xmlGenericErrorContext,
7883                    "Compiled callback for: '%s'\n", token);
7884#endif
7885    if (ctxt == NULL) {
7886        fprintf(stderr, "callback on %s missing context\n", token);
7887        return;
7888    }
7889    if (define == NULL) {
7890        if (token[0] == '#')
7891            return;
7892        fprintf(stderr, "callback on %s missing define\n", token);
7893        if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7894            ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7895        return;
7896    }
7897    if ((ctxt == NULL) || (define == NULL)) {
7898        fprintf(stderr, "callback on %s missing info\n", token);
7899        if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7900            ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7901        return;
7902    } else if (define->type != XML_RELAXNG_ELEMENT) {
7903        fprintf(stderr, "callback on %s define is not element\n", token);
7904        if (ctxt->errNo == XML_RELAXNG_OK)
7905            ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7906        return;
7907    }
7908    ret = xmlRelaxNGValidateDefinition(ctxt, define);
7909    if (ret != 0)
7910        ctxt->perr = ret;
7911}
7912
7913/**
7914 * xmlRelaxNGValidateCompiledContent:
7915 * @ctxt:  the RelaxNG validation context
7916 * @regexp:  the regular expression as compiled
7917 * @content:  list of children to test against the regexp
7918 *
7919 * Validate the content model of an element or start using the regexp
7920 *
7921 * Returns 0 in case of success, -1 in case of error.
7922 */
7923static int
7924xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7925                                  xmlRegexpPtr regexp, xmlNodePtr content)
7926{
7927    xmlRegExecCtxtPtr exec;
7928    xmlNodePtr cur;
7929    int ret = 0;
7930    int oldperr;
7931
7932    if ((ctxt == NULL) || (regexp == NULL))
7933        return (-1);
7934    oldperr = ctxt->perr;
7935    exec = xmlRegNewExecCtxt(regexp,
7936                             xmlRelaxNGValidateCompiledCallback, ctxt);
7937    ctxt->perr = 0;
7938    cur = content;
7939    while (cur != NULL) {
7940        ctxt->state->seq = cur;
7941        switch (cur->type) {
7942            case XML_TEXT_NODE:
7943            case XML_CDATA_SECTION_NODE:
7944                if (xmlIsBlankNode(cur))
7945                    break;
7946                ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7947                if (ret < 0) {
7948                    VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7949                               cur->parent->name);
7950                }
7951                break;
7952            case XML_ELEMENT_NODE:
7953                if (cur->ns != NULL) {
7954                    ret = xmlRegExecPushString2(exec, cur->name,
7955                                                cur->ns->href, ctxt);
7956                } else {
7957                    ret = xmlRegExecPushString(exec, cur->name, ctxt);
7958                }
7959                if (ret < 0) {
7960                    VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7961                }
7962                break;
7963            default:
7964                break;
7965        }
7966        if (ret < 0)
7967            break;
7968        /*
7969         * Switch to next element
7970         */
7971        cur = cur->next;
7972    }
7973    ret = xmlRegExecPushString(exec, NULL, NULL);
7974    if (ret == 1) {
7975        ret = 0;
7976        ctxt->state->seq = NULL;
7977    } else if (ret == 0) {
7978        /*
7979         * TODO: get some of the names needed to exit the current state of exec
7980         */
7981        VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7982        ret = -1;
7983        if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7984            xmlRelaxNGDumpValidError(ctxt);
7985    } else {
7986        ret = -1;
7987    }
7988    xmlRegFreeExecCtxt(exec);
7989    /*
7990     * There might be content model errors outside of the pure
7991     * regexp validation, e.g. for attribute values.
7992     */
7993    if ((ret == 0) && (ctxt->perr != 0)) {
7994        ret = ctxt->perr;
7995    }
7996    ctxt->perr = oldperr;
7997    return (ret);
7998}
7999
8000/************************************************************************
8001 * 									*
8002 * 		Progressive validation of when possible			*
8003 * 									*
8004 ************************************************************************/
8005static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8006                                           xmlRelaxNGDefinePtr defines);
8007static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
8008                                        int dolog);
8009static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
8010
8011/**
8012 * xmlRelaxNGElemPush:
8013 * @ctxt:  the validation context
8014 * @exec:  the regexp runtime for the new content model
8015 *
8016 * Push a new regexp for the current node content model on the stack
8017 *
8018 * Returns 0 in case of success and -1 in case of error.
8019 */
8020static int
8021xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
8022{
8023    if (ctxt->elemTab == NULL) {
8024        ctxt->elemMax = 10;
8025        ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
8026                                                        sizeof
8027                                                        (xmlRegExecCtxtPtr));
8028        if (ctxt->elemTab == NULL) {
8029            xmlRngVErrMemory(ctxt, "validating\n");
8030            return (-1);
8031        }
8032    }
8033    if (ctxt->elemNr >= ctxt->elemMax) {
8034        ctxt->elemMax *= 2;
8035        ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
8036                                                         ctxt->elemMax *
8037                                                         sizeof
8038                                                         (xmlRegExecCtxtPtr));
8039        if (ctxt->elemTab == NULL) {
8040            xmlRngVErrMemory(ctxt, "validating\n");
8041            return (-1);
8042        }
8043    }
8044    ctxt->elemTab[ctxt->elemNr++] = exec;
8045    ctxt->elem = exec;
8046    return (0);
8047}
8048
8049/**
8050 * xmlRelaxNGElemPop:
8051 * @ctxt:  the validation context
8052 *
8053 * Pop the regexp of the current node content model from the stack
8054 *
8055 * Returns the exec or NULL if empty
8056 */
8057static xmlRegExecCtxtPtr
8058xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
8059{
8060    xmlRegExecCtxtPtr ret;
8061
8062    if (ctxt->elemNr <= 0)
8063        return (NULL);
8064    ctxt->elemNr--;
8065    ret = ctxt->elemTab[ctxt->elemNr];
8066    ctxt->elemTab[ctxt->elemNr] = NULL;
8067    if (ctxt->elemNr > 0)
8068        ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
8069    else
8070        ctxt->elem = NULL;
8071    return (ret);
8072}
8073
8074/**
8075 * xmlRelaxNGValidateProgressiveCallback:
8076 * @exec:  the regular expression instance
8077 * @token:  the token which matched
8078 * @transdata:  callback data, the define for the subelement if available
8079 @ @inputdata:  callback data, the Relax NG validation context
8080 *
8081 * Handle the callback and if needed validate the element children.
8082 * some of the in/out informations are passed via the context in @inputdata.
8083 */
8084static void
8085xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8086                                      ATTRIBUTE_UNUSED,
8087                                      const xmlChar * token,
8088                                      void *transdata, void *inputdata)
8089{
8090    xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
8091    xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
8092    xmlRelaxNGValidStatePtr state, oldstate;
8093    xmlNodePtr node;
8094    int ret = 0, oldflags;
8095
8096#ifdef DEBUG_PROGRESSIVE
8097    xmlGenericError(xmlGenericErrorContext,
8098                    "Progressive callback for: '%s'\n", token);
8099#endif
8100    if (ctxt == NULL) {
8101        fprintf(stderr, "callback on %s missing context\n", token);
8102        return;
8103    }
8104    node = ctxt->pnode;
8105    ctxt->pstate = 1;
8106    if (define == NULL) {
8107        if (token[0] == '#')
8108            return;
8109        fprintf(stderr, "callback on %s missing define\n", token);
8110        if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8111            ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8112        ctxt->pstate = -1;
8113        return;
8114    }
8115    if ((ctxt == NULL) || (define == NULL)) {
8116        fprintf(stderr, "callback on %s missing info\n", token);
8117        if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8118            ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8119        ctxt->pstate = -1;
8120        return;
8121    } else if (define->type != XML_RELAXNG_ELEMENT) {
8122        fprintf(stderr, "callback on %s define is not element\n", token);
8123        if (ctxt->errNo == XML_RELAXNG_OK)
8124            ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8125        ctxt->pstate = -1;
8126        return;
8127    }
8128    if (node->type != XML_ELEMENT_NODE) {
8129        VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8130        if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8131            xmlRelaxNGDumpValidError(ctxt);
8132        ctxt->pstate = -1;
8133        return;
8134    }
8135    if (define->contModel == NULL) {
8136        /*
8137         * this node cannot be validated in a streamable fashion
8138         */
8139#ifdef DEBUG_PROGRESSIVE
8140        xmlGenericError(xmlGenericErrorContext,
8141                        "Element '%s' validation is not streamable\n",
8142                        token);
8143#endif
8144        ctxt->pstate = 0;
8145        ctxt->pdef = define;
8146        return;
8147    }
8148    exec = xmlRegNewExecCtxt(define->contModel,
8149                             xmlRelaxNGValidateProgressiveCallback, ctxt);
8150    if (exec == NULL) {
8151        ctxt->pstate = -1;
8152        return;
8153    }
8154    xmlRelaxNGElemPush(ctxt, exec);
8155
8156    /*
8157     * Validate the attributes part of the content.
8158     */
8159    state = xmlRelaxNGNewValidState(ctxt, node);
8160    if (state == NULL) {
8161        ctxt->pstate = -1;
8162        return;
8163    }
8164    oldstate = ctxt->state;
8165    ctxt->state = state;
8166    if (define->attrs != NULL) {
8167        ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8168        if (ret != 0) {
8169            ctxt->pstate = -1;
8170            VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8171        }
8172    }
8173    if (ctxt->state != NULL) {
8174        ctxt->state->seq = NULL;
8175        ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8176        if (ret != 0) {
8177            ctxt->pstate = -1;
8178        }
8179        xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8180    } else if (ctxt->states != NULL) {
8181        int tmp = -1, i;
8182
8183        oldflags = ctxt->flags;
8184
8185        for (i = 0; i < ctxt->states->nbState; i++) {
8186            state = ctxt->states->tabState[i];
8187            ctxt->state = state;
8188            ctxt->state->seq = NULL;
8189
8190            if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8191                tmp = 0;
8192                break;
8193            }
8194        }
8195        if (tmp != 0) {
8196            /*
8197             * validation error, log the message for the "best" one
8198             */
8199            ctxt->flags |= FLAGS_IGNORABLE;
8200            xmlRelaxNGLogBestError(ctxt);
8201        }
8202        for (i = 0; i < ctxt->states->nbState; i++) {
8203            xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8204        }
8205        xmlRelaxNGFreeStates(ctxt, ctxt->states);
8206        ctxt->states = NULL;
8207        if ((ret == 0) && (tmp == -1))
8208            ctxt->pstate = -1;
8209        ctxt->flags = oldflags;
8210    }
8211    if (ctxt->pstate == -1) {
8212        if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8213            xmlRelaxNGDumpValidError(ctxt);
8214        }
8215    }
8216    ctxt->state = oldstate;
8217}
8218
8219/**
8220 * xmlRelaxNGValidatePushElement:
8221 * @ctxt:  the validation context
8222 * @doc:  a document instance
8223 * @elem:  an element instance
8224 *
8225 * Push a new element start on the RelaxNG validation stack.
8226 *
8227 * returns 1 if no validation problem was found or 0 if validating the
8228 *         element requires a full node, and -1 in case of error.
8229 */
8230int
8231xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8232                              xmlDocPtr doc ATTRIBUTE_UNUSED,
8233                              xmlNodePtr elem)
8234{
8235    int ret = 1;
8236
8237    if ((ctxt == NULL) || (elem == NULL))
8238        return (-1);
8239
8240#ifdef DEBUG_PROGRESSIVE
8241    xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8242#endif
8243    if (ctxt->elem == 0) {
8244        xmlRelaxNGPtr schema;
8245        xmlRelaxNGGrammarPtr grammar;
8246        xmlRegExecCtxtPtr exec;
8247        xmlRelaxNGDefinePtr define;
8248
8249        schema = ctxt->schema;
8250        if (schema == NULL) {
8251            VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8252            return (-1);
8253        }
8254        grammar = schema->topgrammar;
8255        if ((grammar == NULL) || (grammar->start == NULL)) {
8256            VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8257            return (-1);
8258        }
8259        define = grammar->start;
8260        if (define->contModel == NULL) {
8261            ctxt->pdef = define;
8262            return (0);
8263        }
8264        exec = xmlRegNewExecCtxt(define->contModel,
8265                                 xmlRelaxNGValidateProgressiveCallback,
8266                                 ctxt);
8267        if (exec == NULL) {
8268            return (-1);
8269        }
8270        xmlRelaxNGElemPush(ctxt, exec);
8271    }
8272    ctxt->pnode = elem;
8273    ctxt->pstate = 0;
8274    if (elem->ns != NULL) {
8275        ret =
8276            xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8277                                  ctxt);
8278    } else {
8279        ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8280    }
8281    if (ret < 0) {
8282        VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8283    } else {
8284        if (ctxt->pstate == 0)
8285            ret = 0;
8286        else if (ctxt->pstate < 0)
8287            ret = -1;
8288        else
8289            ret = 1;
8290    }
8291#ifdef DEBUG_PROGRESSIVE
8292    if (ret < 0)
8293        xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8294                        elem->name);
8295#endif
8296    return (ret);
8297}
8298
8299/**
8300 * xmlRelaxNGValidatePushCData:
8301 * @ctxt:  the RelaxNG validation context
8302 * @data:  some character data read
8303 * @len:  the lenght of the data
8304 *
8305 * check the CData parsed for validation in the current stack
8306 *
8307 * returns 1 if no validation problem was found or -1 otherwise
8308 */
8309int
8310xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
8311                            const xmlChar * data, int len ATTRIBUTE_UNUSED)
8312{
8313    int ret = 1;
8314
8315    if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8316        return (-1);
8317
8318#ifdef DEBUG_PROGRESSIVE
8319    xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8320#endif
8321
8322    while (*data != 0) {
8323        if (!IS_BLANK_CH(*data))
8324            break;
8325        data++;
8326    }
8327    if (*data == 0)
8328        return (1);
8329
8330    ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8331    if (ret < 0) {
8332        VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
8333#ifdef DEBUG_PROGRESSIVE
8334        xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
8335#endif
8336
8337        return (-1);
8338    }
8339    return (1);
8340}
8341
8342/**
8343 * xmlRelaxNGValidatePopElement:
8344 * @ctxt:  the RelaxNG validation context
8345 * @doc:  a document instance
8346 * @elem:  an element instance
8347 *
8348 * Pop the element end from the RelaxNG validation stack.
8349 *
8350 * returns 1 if no validation problem was found or 0 otherwise
8351 */
8352int
8353xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8354                             xmlDocPtr doc ATTRIBUTE_UNUSED,
8355                             xmlNodePtr elem)
8356{
8357    int ret;
8358    xmlRegExecCtxtPtr exec;
8359
8360    if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8361        return (-1);
8362#ifdef DEBUG_PROGRESSIVE
8363    xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8364#endif
8365    /*
8366     * verify that we reached a terminal state of the content model.
8367     */
8368    exec = xmlRelaxNGElemPop(ctxt);
8369    ret = xmlRegExecPushString(exec, NULL, NULL);
8370    if (ret == 0) {
8371        /*
8372         * TODO: get some of the names needed to exit the current state of exec
8373         */
8374        VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8375        ret = -1;
8376    } else if (ret < 0) {
8377        ret = -1;
8378    } else {
8379        ret = 1;
8380    }
8381    xmlRegFreeExecCtxt(exec);
8382#ifdef DEBUG_PROGRESSIVE
8383    if (ret < 0)
8384        xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8385                        elem->name);
8386#endif
8387    return (ret);
8388}
8389
8390/**
8391 * xmlRelaxNGValidateFullElement:
8392 * @ctxt:  the validation context
8393 * @doc:  a document instance
8394 * @elem:  an element instance
8395 *
8396 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8397 * 0 and the content of the node has been expanded.
8398 *
8399 * returns 1 if no validation problem was found or -1 in case of error.
8400 */
8401int
8402xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8403                              xmlDocPtr doc ATTRIBUTE_UNUSED,
8404                              xmlNodePtr elem)
8405{
8406    int ret;
8407    xmlRelaxNGValidStatePtr state;
8408
8409    if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8410        return (-1);
8411#ifdef DEBUG_PROGRESSIVE
8412    xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8413#endif
8414    state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8415    if (state == NULL) {
8416        return (-1);
8417    }
8418    state->seq = elem;
8419    ctxt->state = state;
8420    ctxt->errNo = XML_RELAXNG_OK;
8421    ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8422    if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8423        ret = -1;
8424    else
8425        ret = 1;
8426    xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8427    ctxt->state = NULL;
8428#ifdef DEBUG_PROGRESSIVE
8429    if (ret < 0)
8430        xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8431                        elem->name);
8432#endif
8433    return (ret);
8434}
8435
8436/************************************************************************
8437 * 									*
8438 * 		Generic interpreted validation implementation		*
8439 * 									*
8440 ************************************************************************/
8441static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8442                                   xmlRelaxNGDefinePtr define);
8443
8444/**
8445 * xmlRelaxNGSkipIgnored:
8446 * @ctxt:  a schema validation context
8447 * @node:  the top node.
8448 *
8449 * Skip ignorable nodes in that context
8450 *
8451 * Returns the new sibling or NULL in case of error.
8452 */
8453static xmlNodePtr
8454xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8455                      xmlNodePtr node)
8456{
8457    /*
8458     * TODO complete and handle entities
8459     */
8460    while ((node != NULL) &&
8461           ((node->type == XML_COMMENT_NODE) ||
8462            (node->type == XML_PI_NODE) ||
8463	    (node->type == XML_XINCLUDE_START) ||
8464	    (node->type == XML_XINCLUDE_END) ||
8465            (((node->type == XML_TEXT_NODE) ||
8466              (node->type == XML_CDATA_SECTION_NODE)) &&
8467             ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8468              (IS_BLANK_NODE(node)))))) {
8469        node = node->next;
8470    }
8471    return (node);
8472}
8473
8474/**
8475 * xmlRelaxNGNormalize:
8476 * @ctxt:  a schema validation context
8477 * @str:  the string to normalize
8478 *
8479 * Implements the  normalizeWhiteSpace( s ) function from
8480 * section 6.2.9 of the spec
8481 *
8482 * Returns the new string or NULL in case of error.
8483 */
8484static xmlChar *
8485xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8486{
8487    xmlChar *ret, *p;
8488    const xmlChar *tmp;
8489    int len;
8490
8491    if (str == NULL)
8492        return (NULL);
8493    tmp = str;
8494    while (*tmp != 0)
8495        tmp++;
8496    len = tmp - str;
8497
8498    ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
8499    if (ret == NULL) {
8500        xmlRngVErrMemory(ctxt, "validating\n");
8501        return (NULL);
8502    }
8503    p = ret;
8504    while (IS_BLANK_CH(*str))
8505        str++;
8506    while (*str != 0) {
8507        if (IS_BLANK_CH(*str)) {
8508            while (IS_BLANK_CH(*str))
8509                str++;
8510            if (*str == 0)
8511                break;
8512            *p++ = ' ';
8513        } else
8514            *p++ = *str++;
8515    }
8516    *p = 0;
8517    return (ret);
8518}
8519
8520/**
8521 * xmlRelaxNGValidateDatatype:
8522 * @ctxt:  a Relax-NG validation context
8523 * @value:  the string value
8524 * @type:  the datatype definition
8525 * @node:  the node
8526 *
8527 * Validate the given value against the dataype
8528 *
8529 * Returns 0 if the validation succeeded or an error code.
8530 */
8531static int
8532xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8533                           const xmlChar * value,
8534                           xmlRelaxNGDefinePtr define, xmlNodePtr node)
8535{
8536    int ret, tmp;
8537    xmlRelaxNGTypeLibraryPtr lib;
8538    void *result = NULL;
8539    xmlRelaxNGDefinePtr cur;
8540
8541    if ((define == NULL) || (define->data == NULL)) {
8542        return (-1);
8543    }
8544    lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8545    if (lib->check != NULL) {
8546        if ((define->attrs != NULL) &&
8547            (define->attrs->type == XML_RELAXNG_PARAM)) {
8548            ret =
8549                lib->check(lib->data, define->name, value, &result, node);
8550        } else {
8551            ret = lib->check(lib->data, define->name, value, NULL, node);
8552        }
8553    } else
8554        ret = -1;
8555    if (ret < 0) {
8556        VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8557        if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8558            lib->freef(lib->data, result);
8559        return (-1);
8560    } else if (ret == 1) {
8561        ret = 0;
8562    } else if (ret == 2) {
8563        VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
8564    } else {
8565        VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8566        ret = -1;
8567    }
8568    cur = define->attrs;
8569    while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8570        if (lib->facet != NULL) {
8571            tmp = lib->facet(lib->data, define->name, cur->name,
8572                             cur->value, value, result);
8573            if (tmp != 0)
8574                ret = -1;
8575        }
8576        cur = cur->next;
8577    }
8578    if ((ret == 0) && (define->content != NULL)) {
8579        const xmlChar *oldvalue, *oldendvalue;
8580
8581        oldvalue = ctxt->state->value;
8582        oldendvalue = ctxt->state->endvalue;
8583        ctxt->state->value = (xmlChar *) value;
8584        ctxt->state->endvalue = NULL;
8585        ret = xmlRelaxNGValidateValue(ctxt, define->content);
8586        ctxt->state->value = (xmlChar *) oldvalue;
8587        ctxt->state->endvalue = (xmlChar *) oldendvalue;
8588    }
8589    if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8590        lib->freef(lib->data, result);
8591    return (ret);
8592}
8593
8594/**
8595 * xmlRelaxNGNextValue:
8596 * @ctxt:  a Relax-NG validation context
8597 *
8598 * Skip to the next value when validating within a list
8599 *
8600 * Returns 0 if the operation succeeded or an error code.
8601 */
8602static int
8603xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8604{
8605    xmlChar *cur;
8606
8607    cur = ctxt->state->value;
8608    if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8609        ctxt->state->value = NULL;
8610        ctxt->state->endvalue = NULL;
8611        return (0);
8612    }
8613    while (*cur != 0)
8614        cur++;
8615    while ((cur != ctxt->state->endvalue) && (*cur == 0))
8616        cur++;
8617    if (cur == ctxt->state->endvalue)
8618        ctxt->state->value = NULL;
8619    else
8620        ctxt->state->value = cur;
8621    return (0);
8622}
8623
8624/**
8625 * xmlRelaxNGValidateValueList:
8626 * @ctxt:  a Relax-NG validation context
8627 * @defines:  the list of definitions to verify
8628 *
8629 * Validate the given set of definitions for the current value
8630 *
8631 * Returns 0 if the validation succeeded or an error code.
8632 */
8633static int
8634xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8635                            xmlRelaxNGDefinePtr defines)
8636{
8637    int ret = 0;
8638
8639    while (defines != NULL) {
8640        ret = xmlRelaxNGValidateValue(ctxt, defines);
8641        if (ret != 0)
8642            break;
8643        defines = defines->next;
8644    }
8645    return (ret);
8646}
8647
8648/**
8649 * xmlRelaxNGValidateValue:
8650 * @ctxt:  a Relax-NG validation context
8651 * @define:  the definition to verify
8652 *
8653 * Validate the given definition for the current value
8654 *
8655 * Returns 0 if the validation succeeded or an error code.
8656 */
8657static int
8658xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8659                        xmlRelaxNGDefinePtr define)
8660{
8661    int ret = 0, oldflags;
8662    xmlChar *value;
8663
8664    value = ctxt->state->value;
8665    switch (define->type) {
8666        case XML_RELAXNG_EMPTY:{
8667                if ((value != NULL) && (value[0] != 0)) {
8668                    int idx = 0;
8669
8670                    while (IS_BLANK_CH(value[idx]))
8671                        idx++;
8672                    if (value[idx] != 0)
8673                        ret = -1;
8674                }
8675                break;
8676            }
8677        case XML_RELAXNG_TEXT:
8678            break;
8679        case XML_RELAXNG_VALUE:{
8680                if (!xmlStrEqual(value, define->value)) {
8681                    if (define->name != NULL) {
8682                        xmlRelaxNGTypeLibraryPtr lib;
8683
8684                        lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8685                        if ((lib != NULL) && (lib->comp != NULL)) {
8686                            ret = lib->comp(lib->data, define->name,
8687                                            define->value, define->node,
8688                                            (void *) define->attrs,
8689                                            value, ctxt->state->node);
8690                        } else
8691                            ret = -1;
8692                        if (ret < 0) {
8693                            VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8694                                       define->name);
8695                            return (-1);
8696                        } else if (ret == 1) {
8697                            ret = 0;
8698                        } else {
8699                            ret = -1;
8700                        }
8701                    } else {
8702                        xmlChar *nval, *nvalue;
8703
8704                        /*
8705                         * TODO: trivial optimizations are possible by
8706                         * computing at compile-time
8707                         */
8708                        nval = xmlRelaxNGNormalize(ctxt, define->value);
8709                        nvalue = xmlRelaxNGNormalize(ctxt, value);
8710
8711                        if ((nval == NULL) || (nvalue == NULL) ||
8712                            (!xmlStrEqual(nval, nvalue)))
8713                            ret = -1;
8714                        if (nval != NULL)
8715                            xmlFree(nval);
8716                        if (nvalue != NULL)
8717                            xmlFree(nvalue);
8718                    }
8719                }
8720                if (ret == 0)
8721                    xmlRelaxNGNextValue(ctxt);
8722                break;
8723            }
8724        case XML_RELAXNG_DATATYPE:{
8725                ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8726                                                 ctxt->state->seq);
8727                if (ret == 0)
8728                    xmlRelaxNGNextValue(ctxt);
8729
8730                break;
8731            }
8732        case XML_RELAXNG_CHOICE:{
8733                xmlRelaxNGDefinePtr list = define->content;
8734                xmlChar *oldvalue;
8735
8736                oldflags = ctxt->flags;
8737                ctxt->flags |= FLAGS_IGNORABLE;
8738
8739                oldvalue = ctxt->state->value;
8740                while (list != NULL) {
8741                    ret = xmlRelaxNGValidateValue(ctxt, list);
8742                    if (ret == 0) {
8743                        break;
8744                    }
8745                    ctxt->state->value = oldvalue;
8746                    list = list->next;
8747                }
8748                ctxt->flags = oldflags;
8749                if (ret != 0) {
8750                    if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8751                        xmlRelaxNGDumpValidError(ctxt);
8752                } else {
8753                    if (ctxt->errNr > 0)
8754                        xmlRelaxNGPopErrors(ctxt, 0);
8755                }
8756                break;
8757            }
8758        case XML_RELAXNG_LIST:{
8759                xmlRelaxNGDefinePtr list = define->content;
8760                xmlChar *oldvalue, *oldend, *val, *cur;
8761
8762#ifdef DEBUG_LIST
8763                int nb_values = 0;
8764#endif
8765
8766                oldvalue = ctxt->state->value;
8767                oldend = ctxt->state->endvalue;
8768
8769                val = xmlStrdup(oldvalue);
8770                if (val == NULL) {
8771                    val = xmlStrdup(BAD_CAST "");
8772                }
8773                if (val == NULL) {
8774                    VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8775                    return (-1);
8776                }
8777                cur = val;
8778                while (*cur != 0) {
8779                    if (IS_BLANK_CH(*cur)) {
8780                        *cur = 0;
8781                        cur++;
8782#ifdef DEBUG_LIST
8783                        nb_values++;
8784#endif
8785                        while (IS_BLANK_CH(*cur))
8786                            *cur++ = 0;
8787                    } else
8788                        cur++;
8789                }
8790#ifdef DEBUG_LIST
8791                xmlGenericError(xmlGenericErrorContext,
8792                                "list value: '%s' found %d items\n",
8793                                oldvalue, nb_values);
8794                nb_values = 0;
8795#endif
8796                ctxt->state->endvalue = cur;
8797                cur = val;
8798                while ((*cur == 0) && (cur != ctxt->state->endvalue))
8799                    cur++;
8800
8801                ctxt->state->value = cur;
8802
8803                while (list != NULL) {
8804                    if (ctxt->state->value == ctxt->state->endvalue)
8805                        ctxt->state->value = NULL;
8806                    ret = xmlRelaxNGValidateValue(ctxt, list);
8807                    if (ret != 0) {
8808#ifdef DEBUG_LIST
8809                        xmlGenericError(xmlGenericErrorContext,
8810                                        "Failed to validate value: '%s' with %d rule\n",
8811                                        ctxt->state->value, nb_values);
8812#endif
8813                        break;
8814                    }
8815#ifdef DEBUG_LIST
8816                    nb_values++;
8817#endif
8818                    list = list->next;
8819                }
8820
8821                if ((ret == 0) && (ctxt->state->value != NULL) &&
8822                    (ctxt->state->value != ctxt->state->endvalue)) {
8823                    VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8824                               ctxt->state->value);
8825                    ret = -1;
8826                }
8827                xmlFree(val);
8828                ctxt->state->value = oldvalue;
8829                ctxt->state->endvalue = oldend;
8830                break;
8831            }
8832        case XML_RELAXNG_ONEORMORE:
8833            ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8834            if (ret != 0) {
8835                break;
8836            }
8837            /* no break on purpose */
8838        case XML_RELAXNG_ZEROORMORE:{
8839                xmlChar *cur, *temp;
8840
8841                oldflags = ctxt->flags;
8842                ctxt->flags |= FLAGS_IGNORABLE;
8843                cur = ctxt->state->value;
8844                temp = NULL;
8845                while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8846                       (temp != cur)) {
8847                    temp = cur;
8848                    ret =
8849                        xmlRelaxNGValidateValueList(ctxt, define->content);
8850                    if (ret != 0) {
8851                        ctxt->state->value = temp;
8852                        ret = 0;
8853                        break;
8854                    }
8855                    cur = ctxt->state->value;
8856                }
8857                ctxt->flags = oldflags;
8858		if (ctxt->errNr > 0)
8859		    xmlRelaxNGPopErrors(ctxt, 0);
8860                break;
8861            }
8862        case XML_RELAXNG_EXCEPT:{
8863                xmlRelaxNGDefinePtr list;
8864
8865                list = define->content;
8866                while (list != NULL) {
8867                    ret = xmlRelaxNGValidateValue(ctxt, list);
8868                    if (ret == 0) {
8869                        ret = -1;
8870                        break;
8871                    } else
8872                        ret = 0;
8873                    list = list->next;
8874                }
8875                break;
8876            }
8877        case XML_RELAXNG_DEF:
8878        case XML_RELAXNG_GROUP:{
8879                xmlRelaxNGDefinePtr list;
8880
8881                list = define->content;
8882                while (list != NULL) {
8883                    ret = xmlRelaxNGValidateValue(ctxt, list);
8884                    if (ret != 0) {
8885                        ret = -1;
8886                        break;
8887                    } else
8888                        ret = 0;
8889                    list = list->next;
8890                }
8891                break;
8892            }
8893        case XML_RELAXNG_REF:
8894        case XML_RELAXNG_PARENTREF:
8895	    if (define->content == NULL) {
8896                VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8897                ret = -1;
8898	    } else {
8899                ret = xmlRelaxNGValidateValue(ctxt, define->content);
8900            }
8901            break;
8902        default:
8903            TODO ret = -1;
8904    }
8905    return (ret);
8906}
8907
8908/**
8909 * xmlRelaxNGValidateValueContent:
8910 * @ctxt:  a Relax-NG validation context
8911 * @defines:  the list of definitions to verify
8912 *
8913 * Validate the given definitions for the current value
8914 *
8915 * Returns 0 if the validation succeeded or an error code.
8916 */
8917static int
8918xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8919                               xmlRelaxNGDefinePtr defines)
8920{
8921    int ret = 0;
8922
8923    while (defines != NULL) {
8924        ret = xmlRelaxNGValidateValue(ctxt, defines);
8925        if (ret != 0)
8926            break;
8927        defines = defines->next;
8928    }
8929    return (ret);
8930}
8931
8932/**
8933 * xmlRelaxNGAttributeMatch:
8934 * @ctxt:  a Relax-NG validation context
8935 * @define:  the definition to check
8936 * @prop:  the attribute
8937 *
8938 * Check if the attribute matches the definition nameClass
8939 *
8940 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8941 */
8942static int
8943xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8944                         xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8945{
8946    int ret;
8947
8948    if (define->name != NULL) {
8949        if (!xmlStrEqual(define->name, prop->name))
8950            return (0);
8951    }
8952    if (define->ns != NULL) {
8953        if (define->ns[0] == 0) {
8954            if (prop->ns != NULL)
8955                return (0);
8956        } else {
8957            if ((prop->ns == NULL) ||
8958                (!xmlStrEqual(define->ns, prop->ns->href)))
8959                return (0);
8960        }
8961    }
8962    if (define->nameClass == NULL)
8963        return (1);
8964    define = define->nameClass;
8965    if (define->type == XML_RELAXNG_EXCEPT) {
8966        xmlRelaxNGDefinePtr list;
8967
8968        list = define->content;
8969        while (list != NULL) {
8970            ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8971            if (ret == 1)
8972                return (0);
8973            if (ret < 0)
8974                return (ret);
8975            list = list->next;
8976        }
8977    } else {
8978    TODO}
8979    return (1);
8980}
8981
8982/**
8983 * xmlRelaxNGValidateAttribute:
8984 * @ctxt:  a Relax-NG validation context
8985 * @define:  the definition to verify
8986 *
8987 * Validate the given attribute definition for that node
8988 *
8989 * Returns 0 if the validation succeeded or an error code.
8990 */
8991static int
8992xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8993                            xmlRelaxNGDefinePtr define)
8994{
8995    int ret = 0, i;
8996    xmlChar *value, *oldvalue;
8997    xmlAttrPtr prop = NULL, tmp;
8998    xmlNodePtr oldseq;
8999
9000    if (ctxt->state->nbAttrLeft <= 0)
9001        return (-1);
9002    if (define->name != NULL) {
9003        for (i = 0; i < ctxt->state->nbAttrs; i++) {
9004            tmp = ctxt->state->attrs[i];
9005            if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
9006                if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
9007                     (tmp->ns == NULL)) ||
9008                    ((tmp->ns != NULL) &&
9009                     (xmlStrEqual(define->ns, tmp->ns->href)))) {
9010                    prop = tmp;
9011                    break;
9012                }
9013            }
9014        }
9015        if (prop != NULL) {
9016            value = xmlNodeListGetString(prop->doc, prop->children, 1);
9017            oldvalue = ctxt->state->value;
9018            oldseq = ctxt->state->seq;
9019            ctxt->state->seq = (xmlNodePtr) prop;
9020            ctxt->state->value = value;
9021            ctxt->state->endvalue = NULL;
9022            ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9023            if (ctxt->state->value != NULL)
9024                value = ctxt->state->value;
9025            if (value != NULL)
9026                xmlFree(value);
9027            ctxt->state->value = oldvalue;
9028            ctxt->state->seq = oldseq;
9029            if (ret == 0) {
9030                /*
9031                 * flag the attribute as processed
9032                 */
9033                ctxt->state->attrs[i] = NULL;
9034                ctxt->state->nbAttrLeft--;
9035            }
9036        } else {
9037            ret = -1;
9038        }
9039#ifdef DEBUG
9040        xmlGenericError(xmlGenericErrorContext,
9041                        "xmlRelaxNGValidateAttribute(%s): %d\n",
9042                        define->name, ret);
9043#endif
9044    } else {
9045        for (i = 0; i < ctxt->state->nbAttrs; i++) {
9046            tmp = ctxt->state->attrs[i];
9047            if ((tmp != NULL) &&
9048                (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
9049                prop = tmp;
9050                break;
9051            }
9052        }
9053        if (prop != NULL) {
9054            value = xmlNodeListGetString(prop->doc, prop->children, 1);
9055            oldvalue = ctxt->state->value;
9056            oldseq = ctxt->state->seq;
9057            ctxt->state->seq = (xmlNodePtr) prop;
9058            ctxt->state->value = value;
9059            ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9060            if (ctxt->state->value != NULL)
9061                value = ctxt->state->value;
9062            if (value != NULL)
9063                xmlFree(value);
9064            ctxt->state->value = oldvalue;
9065            ctxt->state->seq = oldseq;
9066            if (ret == 0) {
9067                /*
9068                 * flag the attribute as processed
9069                 */
9070                ctxt->state->attrs[i] = NULL;
9071                ctxt->state->nbAttrLeft--;
9072            }
9073        } else {
9074            ret = -1;
9075        }
9076#ifdef DEBUG
9077        if (define->ns != NULL) {
9078            xmlGenericError(xmlGenericErrorContext,
9079                            "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9080                            define->ns, ret);
9081        } else {
9082            xmlGenericError(xmlGenericErrorContext,
9083                            "xmlRelaxNGValidateAttribute(anyName): %d\n",
9084                            ret);
9085        }
9086#endif
9087    }
9088
9089    return (ret);
9090}
9091
9092/**
9093 * xmlRelaxNGValidateAttributeList:
9094 * @ctxt:  a Relax-NG validation context
9095 * @define:  the list of definition to verify
9096 *
9097 * Validate the given node against the list of attribute definitions
9098 *
9099 * Returns 0 if the validation succeeded or an error code.
9100 */
9101static int
9102xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
9103                                xmlRelaxNGDefinePtr defines)
9104{
9105    int ret = 0, res;
9106    int needmore = 0;
9107    xmlRelaxNGDefinePtr cur;
9108
9109    cur = defines;
9110    while (cur != NULL) {
9111        if (cur->type == XML_RELAXNG_ATTRIBUTE) {
9112            if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9113                ret = -1;
9114        } else
9115            needmore = 1;
9116        cur = cur->next;
9117    }
9118    if (!needmore)
9119        return (ret);
9120    cur = defines;
9121    while (cur != NULL) {
9122        if (cur->type != XML_RELAXNG_ATTRIBUTE) {
9123            if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9124                res = xmlRelaxNGValidateDefinition(ctxt, cur);
9125                if (res < 0)
9126                    ret = -1;
9127            } else {
9128                VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9129                return (-1);
9130            }
9131            if (res == -1)      /* continues on -2 */
9132                break;
9133        }
9134        cur = cur->next;
9135    }
9136
9137    return (ret);
9138}
9139
9140/**
9141 * xmlRelaxNGNodeMatchesList:
9142 * @node:  the node
9143 * @list:  a NULL terminated array of definitions
9144 *
9145 * Check if a node can be matched by one of the definitions
9146 *
9147 * Returns 1 if matches 0 otherwise
9148 */
9149static int
9150xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9151{
9152    xmlRelaxNGDefinePtr cur;
9153    int i = 0, tmp;
9154
9155    if ((node == NULL) || (list == NULL))
9156        return (0);
9157
9158    cur = list[i++];
9159    while (cur != NULL) {
9160        if ((node->type == XML_ELEMENT_NODE) &&
9161            (cur->type == XML_RELAXNG_ELEMENT)) {
9162            tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9163            if (tmp == 1)
9164                return (1);
9165        } else if (((node->type == XML_TEXT_NODE) ||
9166                    (node->type == XML_CDATA_SECTION_NODE)) &&
9167                   (cur->type == XML_RELAXNG_TEXT)) {
9168            return (1);
9169        }
9170        cur = list[i++];
9171    }
9172    return (0);
9173}
9174
9175/**
9176 * xmlRelaxNGValidateInterleave:
9177 * @ctxt:  a Relax-NG validation context
9178 * @define:  the definition to verify
9179 *
9180 * Validate an interleave definition for a node.
9181 *
9182 * Returns 0 if the validation succeeded or an error code.
9183 */
9184static int
9185xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9186                             xmlRelaxNGDefinePtr define)
9187{
9188    int ret = 0, i, nbgroups;
9189    int errNr = ctxt->errNr;
9190    int oldflags;
9191
9192    xmlRelaxNGValidStatePtr oldstate;
9193    xmlRelaxNGPartitionPtr partitions;
9194    xmlRelaxNGInterleaveGroupPtr group = NULL;
9195    xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9196    xmlNodePtr *list = NULL, *lasts = NULL;
9197
9198    if (define->data != NULL) {
9199        partitions = (xmlRelaxNGPartitionPtr) define->data;
9200        nbgroups = partitions->nbgroups;
9201    } else {
9202        VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9203        return (-1);
9204    }
9205    /*
9206     * Optimizations for MIXED
9207     */
9208    oldflags = ctxt->flags;
9209    if (define->dflags & IS_MIXED) {
9210        ctxt->flags |= FLAGS_MIXED_CONTENT;
9211        if (nbgroups == 2) {
9212            /*
9213             * this is a pure <mixed> case
9214             */
9215            if (ctxt->state != NULL)
9216                ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9217                                                         ctxt->state->seq);
9218            if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9219                ret = xmlRelaxNGValidateDefinition(ctxt,
9220                                                   partitions->groups[1]->
9221                                                   rule);
9222            else
9223                ret = xmlRelaxNGValidateDefinition(ctxt,
9224                                                   partitions->groups[0]->
9225                                                   rule);
9226            if (ret == 0) {
9227                if (ctxt->state != NULL)
9228                    ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9229                                                             ctxt->state->
9230                                                             seq);
9231            }
9232            ctxt->flags = oldflags;
9233            return (ret);
9234        }
9235    }
9236
9237    /*
9238     * Build arrays to store the first and last node of the chain
9239     * pertaining to each group
9240     */
9241    list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9242    if (list == NULL) {
9243        xmlRngVErrMemory(ctxt, "validating\n");
9244        return (-1);
9245    }
9246    memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9247    lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9248    if (lasts == NULL) {
9249        xmlRngVErrMemory(ctxt, "validating\n");
9250        return (-1);
9251    }
9252    memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9253
9254    /*
9255     * Walk the sequence of children finding the right group and
9256     * sorting them in sequences.
9257     */
9258    cur = ctxt->state->seq;
9259    cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9260    start = cur;
9261    while (cur != NULL) {
9262        ctxt->state->seq = cur;
9263        if ((partitions->triage != NULL) &&
9264            (partitions->flags & IS_DETERMINIST)) {
9265            void *tmp = NULL;
9266
9267            if ((cur->type == XML_TEXT_NODE) ||
9268                (cur->type == XML_CDATA_SECTION_NODE)) {
9269                tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9270                                     NULL);
9271            } else if (cur->type == XML_ELEMENT_NODE) {
9272                if (cur->ns != NULL) {
9273                    tmp = xmlHashLookup2(partitions->triage, cur->name,
9274                                         cur->ns->href);
9275                    if (tmp == NULL)
9276                        tmp = xmlHashLookup2(partitions->triage,
9277                                             BAD_CAST "#any",
9278                                             cur->ns->href);
9279                } else
9280                    tmp =
9281                        xmlHashLookup2(partitions->triage, cur->name,
9282                                       NULL);
9283                if (tmp == NULL)
9284                    tmp =
9285                        xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9286                                       NULL);
9287            }
9288
9289            if (tmp == NULL) {
9290                i = nbgroups;
9291            } else {
9292                i = ((long) tmp) - 1;
9293                if (partitions->flags & IS_NEEDCHECK) {
9294                    group = partitions->groups[i];
9295                    if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9296                        i = nbgroups;
9297                }
9298            }
9299        } else {
9300            for (i = 0; i < nbgroups; i++) {
9301                group = partitions->groups[i];
9302                if (group == NULL)
9303                    continue;
9304                if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9305                    break;
9306            }
9307        }
9308        /*
9309         * We break as soon as an element not matched is found
9310         */
9311        if (i >= nbgroups) {
9312            break;
9313        }
9314        if (lasts[i] != NULL) {
9315            lasts[i]->next = cur;
9316            lasts[i] = cur;
9317        } else {
9318            list[i] = cur;
9319            lasts[i] = cur;
9320        }
9321        if (cur->next != NULL)
9322            lastchg = cur->next;
9323        else
9324            lastchg = cur;
9325        cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9326    }
9327    if (ret != 0) {
9328        VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9329        ret = -1;
9330        goto done;
9331    }
9332    lastelem = cur;
9333    oldstate = ctxt->state;
9334    for (i = 0; i < nbgroups; i++) {
9335        ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9336        group = partitions->groups[i];
9337        if (lasts[i] != NULL) {
9338            last = lasts[i]->next;
9339            lasts[i]->next = NULL;
9340        }
9341        ctxt->state->seq = list[i];
9342        ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9343        if (ret != 0)
9344            break;
9345        if (ctxt->state != NULL) {
9346            cur = ctxt->state->seq;
9347            cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9348            xmlRelaxNGFreeValidState(ctxt, oldstate);
9349            oldstate = ctxt->state;
9350            ctxt->state = NULL;
9351            if (cur != NULL) {
9352                VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9353                ret = -1;
9354                ctxt->state = oldstate;
9355                goto done;
9356            }
9357        } else if (ctxt->states != NULL) {
9358            int j;
9359            int found = 0;
9360	    int best = -1;
9361	    int lowattr = -1;
9362
9363	    /*
9364	     * PBM: what happen if there is attributes checks in the interleaves
9365	     */
9366
9367            for (j = 0; j < ctxt->states->nbState; j++) {
9368                cur = ctxt->states->tabState[j]->seq;
9369                cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9370                if (cur == NULL) {
9371		    if (found == 0) {
9372		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9373			best = j;
9374		    }
9375                    found = 1;
9376		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9377		        /* try  to keep the latest one to mach old heuristic */
9378		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9379			best = j;
9380		    }
9381                    if (lowattr == 0)
9382		        break;
9383                } else if (found == 0) {
9384                    if (lowattr == -1) {
9385		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9386			best = j;
9387		    } else
9388		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr)  {
9389		        /* try  to keep the latest one to mach old heuristic */
9390		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9391			best = j;
9392		    }
9393		}
9394            }
9395	    /*
9396	     * BIG PBM: here we pick only one restarting point :-(
9397	     */
9398            if (ctxt->states->nbState > 0) {
9399                xmlRelaxNGFreeValidState(ctxt, oldstate);
9400		if (best != -1) {
9401		    oldstate = ctxt->states->tabState[best];
9402		    ctxt->states->tabState[best] = NULL;
9403		} else {
9404		    oldstate =
9405			ctxt->states->tabState[ctxt->states->nbState - 1];
9406                    ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
9407                    ctxt->states->nbState--;
9408		}
9409            }
9410            for (j = 0; j < ctxt->states->nbState ; j++) {
9411                xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9412            }
9413            xmlRelaxNGFreeStates(ctxt, ctxt->states);
9414            ctxt->states = NULL;
9415            if (found == 0) {
9416                VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9417                ret = -1;
9418                ctxt->state = oldstate;
9419                goto done;
9420            }
9421        } else {
9422            ret = -1;
9423            break;
9424        }
9425        if (lasts[i] != NULL) {
9426            lasts[i]->next = last;
9427        }
9428    }
9429    if (ctxt->state != NULL)
9430        xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9431    ctxt->state = oldstate;
9432    ctxt->state->seq = lastelem;
9433    if (ret != 0) {
9434        VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9435        ret = -1;
9436        goto done;
9437    }
9438
9439  done:
9440    ctxt->flags = oldflags;
9441    /*
9442     * builds the next links chain from the prev one
9443     */
9444    cur = lastchg;
9445    while (cur != NULL) {
9446        if ((cur == start) || (cur->prev == NULL))
9447            break;
9448        cur->prev->next = cur;
9449        cur = cur->prev;
9450    }
9451    if (ret == 0) {
9452        if (ctxt->errNr > errNr)
9453            xmlRelaxNGPopErrors(ctxt, errNr);
9454    }
9455
9456    xmlFree(list);
9457    xmlFree(lasts);
9458    return (ret);
9459}
9460
9461/**
9462 * xmlRelaxNGValidateDefinitionList:
9463 * @ctxt:  a Relax-NG validation context
9464 * @define:  the list of definition to verify
9465 *
9466 * Validate the given node content against the (list) of definitions
9467 *
9468 * Returns 0 if the validation succeeded or an error code.
9469 */
9470static int
9471xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9472                                 xmlRelaxNGDefinePtr defines)
9473{
9474    int ret = 0, res;
9475
9476
9477    if (defines == NULL) {
9478        VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9479                   BAD_CAST "NULL definition list");
9480        return (-1);
9481    }
9482    while (defines != NULL) {
9483        if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9484            res = xmlRelaxNGValidateDefinition(ctxt, defines);
9485            if (res < 0)
9486                ret = -1;
9487        } else {
9488            VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9489            return (-1);
9490        }
9491        if (res == -1)          /* continues on -2 */
9492            break;
9493        defines = defines->next;
9494    }
9495
9496    return (ret);
9497}
9498
9499/**
9500 * xmlRelaxNGElementMatch:
9501 * @ctxt:  a Relax-NG validation context
9502 * @define:  the definition to check
9503 * @elem:  the element
9504 *
9505 * Check if the element matches the definition nameClass
9506 *
9507 * Returns 1 if the element matches, 0 if no, or -1 in case of error
9508 */
9509static int
9510xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9511                       xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9512{
9513    int ret = 0, oldflags = 0;
9514
9515    if (define->name != NULL) {
9516        if (!xmlStrEqual(elem->name, define->name)) {
9517            VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9518            return (0);
9519        }
9520    }
9521    if ((define->ns != NULL) && (define->ns[0] != 0)) {
9522        if (elem->ns == NULL) {
9523            VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9524            return (0);
9525        } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9526            VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9527                       elem->name, define->ns);
9528            return (0);
9529        }
9530    } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9531               (define->name == NULL)) {
9532        VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9533        return (0);
9534    } else if ((elem->ns != NULL) && (define->name != NULL)) {
9535        VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9536        return (0);
9537    }
9538
9539    if (define->nameClass == NULL)
9540        return (1);
9541
9542    define = define->nameClass;
9543    if (define->type == XML_RELAXNG_EXCEPT) {
9544        xmlRelaxNGDefinePtr list;
9545
9546        if (ctxt != NULL) {
9547            oldflags = ctxt->flags;
9548            ctxt->flags |= FLAGS_IGNORABLE;
9549        }
9550
9551        list = define->content;
9552        while (list != NULL) {
9553            ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9554            if (ret == 1) {
9555                if (ctxt != NULL)
9556                    ctxt->flags = oldflags;
9557                return (0);
9558            }
9559            if (ret < 0) {
9560                if (ctxt != NULL)
9561                    ctxt->flags = oldflags;
9562                return (ret);
9563            }
9564            list = list->next;
9565        }
9566        ret = 1;
9567        if (ctxt != NULL) {
9568            ctxt->flags = oldflags;
9569        }
9570    } else if (define->type == XML_RELAXNG_CHOICE) {
9571        xmlRelaxNGDefinePtr list;
9572
9573        if (ctxt != NULL) {
9574            oldflags = ctxt->flags;
9575            ctxt->flags |= FLAGS_IGNORABLE;
9576        }
9577
9578        list = define->nameClass;
9579        while (list != NULL) {
9580            ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9581            if (ret == 1) {
9582                if (ctxt != NULL)
9583                    ctxt->flags = oldflags;
9584                return (1);
9585            }
9586            if (ret < 0) {
9587                if (ctxt != NULL)
9588                    ctxt->flags = oldflags;
9589                return (ret);
9590            }
9591            list = list->next;
9592        }
9593        if (ctxt != NULL) {
9594            if (ret != 0) {
9595                if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9596                    xmlRelaxNGDumpValidError(ctxt);
9597            } else {
9598                if (ctxt->errNr > 0)
9599                    xmlRelaxNGPopErrors(ctxt, 0);
9600            }
9601        }
9602        ret = 0;
9603        if (ctxt != NULL) {
9604            ctxt->flags = oldflags;
9605        }
9606    } else {
9607        TODO ret = -1;
9608    }
9609    return (ret);
9610}
9611
9612/**
9613 * xmlRelaxNGBestState:
9614 * @ctxt:  a Relax-NG validation context
9615 *
9616 * Find the "best" state in the ctxt->states list of states to report
9617 * errors about. I.e. a state with no element left in the child list
9618 * or the one with the less attributes left.
9619 * This is called only if a falidation error was detected
9620 *
9621 * Returns the index of the "best" state or -1 in case of error
9622 */
9623static int
9624xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9625{
9626    xmlRelaxNGValidStatePtr state;
9627    int i, tmp;
9628    int best = -1;
9629    int value = 1000000;
9630
9631    if ((ctxt == NULL) || (ctxt->states == NULL) ||
9632        (ctxt->states->nbState <= 0))
9633        return (-1);
9634
9635    for (i = 0; i < ctxt->states->nbState; i++) {
9636        state = ctxt->states->tabState[i];
9637        if (state == NULL)
9638            continue;
9639        if (state->seq != NULL) {
9640            if ((best == -1) || (value > 100000)) {
9641                value = 100000;
9642                best = i;
9643            }
9644        } else {
9645            tmp = state->nbAttrLeft;
9646            if ((best == -1) || (value > tmp)) {
9647                value = tmp;
9648                best = i;
9649            }
9650        }
9651    }
9652    return (best);
9653}
9654
9655/**
9656 * xmlRelaxNGLogBestError:
9657 * @ctxt:  a Relax-NG validation context
9658 *
9659 * Find the "best" state in the ctxt->states list of states to report
9660 * errors about and log it.
9661 */
9662static void
9663xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9664{
9665    int best;
9666
9667    if ((ctxt == NULL) || (ctxt->states == NULL) ||
9668        (ctxt->states->nbState <= 0))
9669        return;
9670
9671    best = xmlRelaxNGBestState(ctxt);
9672    if ((best >= 0) && (best < ctxt->states->nbState)) {
9673        ctxt->state = ctxt->states->tabState[best];
9674
9675        xmlRelaxNGValidateElementEnd(ctxt, 1);
9676    }
9677}
9678
9679/**
9680 * xmlRelaxNGValidateElementEnd:
9681 * @ctxt:  a Relax-NG validation context
9682 * @dolog:  indicate that error logging should be done
9683 *
9684 * Validate the end of the element, implements check that
9685 * there is nothing left not consumed in the element content
9686 * or in the attribute list.
9687 *
9688 * Returns 0 if the validation succeeded or an error code.
9689 */
9690static int
9691xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
9692{
9693    int i;
9694    xmlRelaxNGValidStatePtr state;
9695
9696    state = ctxt->state;
9697    if (state->seq != NULL) {
9698        state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9699        if (state->seq != NULL) {
9700            if (dolog) {
9701                VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9702                           state->node->name, state->seq->name);
9703            }
9704            return (-1);
9705        }
9706    }
9707    for (i = 0; i < state->nbAttrs; i++) {
9708        if (state->attrs[i] != NULL) {
9709            if (dolog) {
9710                VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9711                           state->attrs[i]->name, state->node->name);
9712            }
9713            return (-1 - i);
9714        }
9715    }
9716    return (0);
9717}
9718
9719/**
9720 * xmlRelaxNGValidateState:
9721 * @ctxt:  a Relax-NG validation context
9722 * @define:  the definition to verify
9723 *
9724 * Validate the current state against the definition
9725 *
9726 * Returns 0 if the validation succeeded or an error code.
9727 */
9728static int
9729xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9730                        xmlRelaxNGDefinePtr define)
9731{
9732    xmlNodePtr node;
9733    int ret = 0, i, tmp, oldflags, errNr;
9734    xmlRelaxNGValidStatePtr oldstate = NULL, state;
9735
9736    if (define == NULL) {
9737        VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9738        return (-1);
9739    }
9740
9741    if (ctxt->state != NULL) {
9742        node = ctxt->state->seq;
9743    } else {
9744        node = NULL;
9745    }
9746#ifdef DEBUG
9747    for (i = 0; i < ctxt->depth; i++)
9748        xmlGenericError(xmlGenericErrorContext, " ");
9749    xmlGenericError(xmlGenericErrorContext,
9750                    "Start validating %s ", xmlRelaxNGDefName(define));
9751    if (define->name != NULL)
9752        xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
9753    if ((node != NULL) && (node->name != NULL))
9754        xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
9755    else
9756        xmlGenericError(xmlGenericErrorContext, "\n");
9757#endif
9758    ctxt->depth++;
9759    switch (define->type) {
9760        case XML_RELAXNG_EMPTY:
9761            node = xmlRelaxNGSkipIgnored(ctxt, node);
9762            ret = 0;
9763            break;
9764        case XML_RELAXNG_NOT_ALLOWED:
9765            ret = -1;
9766            break;
9767        case XML_RELAXNG_TEXT:
9768            while ((node != NULL) &&
9769                   ((node->type == XML_TEXT_NODE) ||
9770                    (node->type == XML_COMMENT_NODE) ||
9771                    (node->type == XML_PI_NODE) ||
9772                    (node->type == XML_CDATA_SECTION_NODE)))
9773                node = node->next;
9774            ctxt->state->seq = node;
9775            break;
9776        case XML_RELAXNG_ELEMENT:
9777            errNr = ctxt->errNr;
9778            node = xmlRelaxNGSkipIgnored(ctxt, node);
9779            if (node == NULL) {
9780                VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9781                ret = -1;
9782                if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9783                    xmlRelaxNGDumpValidError(ctxt);
9784                break;
9785            }
9786            if (node->type != XML_ELEMENT_NODE) {
9787                VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9788                ret = -1;
9789                if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9790                    xmlRelaxNGDumpValidError(ctxt);
9791                break;
9792            }
9793            /*
9794             * This node was already validated successfully against
9795             * this definition.
9796             */
9797            if (node->psvi == define) {
9798                ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9799                if (ctxt->errNr > errNr)
9800                    xmlRelaxNGPopErrors(ctxt, errNr);
9801                if (ctxt->errNr != 0) {
9802                    while ((ctxt->err != NULL) &&
9803                           (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9804                             && (xmlStrEqual(ctxt->err->arg2, node->name)))
9805                            ||
9806                            ((ctxt->err->err ==
9807                              XML_RELAXNG_ERR_ELEMEXTRANS)
9808                             && (xmlStrEqual(ctxt->err->arg1, node->name)))
9809                            || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9810                            || (ctxt->err->err ==
9811                                XML_RELAXNG_ERR_NOTELEM)))
9812                        xmlRelaxNGValidErrorPop(ctxt);
9813                }
9814                break;
9815            }
9816
9817            ret = xmlRelaxNGElementMatch(ctxt, define, node);
9818            if (ret <= 0) {
9819                ret = -1;
9820                if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9821                    xmlRelaxNGDumpValidError(ctxt);
9822                break;
9823            }
9824            ret = 0;
9825            if (ctxt->errNr != 0) {
9826                if (ctxt->errNr > errNr)
9827                    xmlRelaxNGPopErrors(ctxt, errNr);
9828                while ((ctxt->err != NULL) &&
9829                       (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9830                         (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9831                        ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9832                         (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9833                        (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9834                        (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9835                    xmlRelaxNGValidErrorPop(ctxt);
9836            }
9837            errNr = ctxt->errNr;
9838
9839            oldflags = ctxt->flags;
9840            if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9841                ctxt->flags -= FLAGS_MIXED_CONTENT;
9842            }
9843            state = xmlRelaxNGNewValidState(ctxt, node);
9844            if (state == NULL) {
9845                ret = -1;
9846                if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9847                    xmlRelaxNGDumpValidError(ctxt);
9848                break;
9849            }
9850
9851            oldstate = ctxt->state;
9852            ctxt->state = state;
9853            if (define->attrs != NULL) {
9854                tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9855                if (tmp != 0) {
9856                    ret = -1;
9857                    VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9858                }
9859            }
9860            if (define->contModel != NULL) {
9861                xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9862                xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9863                xmlNodePtr nseq;
9864
9865                nstate = xmlRelaxNGNewValidState(ctxt, node);
9866                ctxt->state = nstate;
9867                ctxt->states = NULL;
9868
9869                tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9870                                                        define->contModel,
9871                                                        ctxt->state->seq);
9872                nseq = ctxt->state->seq;
9873                ctxt->state = tmpstate;
9874                ctxt->states = tmpstates;
9875                xmlRelaxNGFreeValidState(ctxt, nstate);
9876
9877#ifdef DEBUG_COMPILE
9878                xmlGenericError(xmlGenericErrorContext,
9879                                "Validating content of '%s' : %d\n",
9880                                define->name, tmp);
9881#endif
9882                if (tmp != 0)
9883                    ret = -1;
9884
9885                if (ctxt->states != NULL) {
9886                    tmp = -1;
9887
9888                    for (i = 0; i < ctxt->states->nbState; i++) {
9889                        state = ctxt->states->tabState[i];
9890                        ctxt->state = state;
9891                        ctxt->state->seq = nseq;
9892
9893                        if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
9894                            tmp = 0;
9895                            break;
9896                        }
9897                    }
9898                    if (tmp != 0) {
9899                        /*
9900                         * validation error, log the message for the "best" one
9901                         */
9902                        ctxt->flags |= FLAGS_IGNORABLE;
9903                        xmlRelaxNGLogBestError(ctxt);
9904                    }
9905                    for (i = 0; i < ctxt->states->nbState; i++) {
9906                        xmlRelaxNGFreeValidState(ctxt,
9907                                                 ctxt->states->
9908                                                 tabState[i]);
9909                    }
9910                    xmlRelaxNGFreeStates(ctxt, ctxt->states);
9911                    ctxt->flags = oldflags;
9912                    ctxt->states = NULL;
9913                    if ((ret == 0) && (tmp == -1))
9914                        ret = -1;
9915                } else {
9916                    state = ctxt->state;
9917		    if (ctxt->state != NULL)
9918			ctxt->state->seq = nseq;
9919                    if (ret == 0)
9920                        ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
9921                    xmlRelaxNGFreeValidState(ctxt, state);
9922                }
9923            } else {
9924                if (define->content != NULL) {
9925                    tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9926                                                           define->
9927                                                           content);
9928                    if (tmp != 0) {
9929                        ret = -1;
9930                        if (ctxt->state == NULL) {
9931                            ctxt->state = oldstate;
9932                            VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9933                                       node->name);
9934                            ctxt->state = NULL;
9935                        } else {
9936                            VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9937                                       node->name);
9938                        }
9939
9940                    }
9941                }
9942                if (ctxt->states != NULL) {
9943                    tmp = -1;
9944
9945                    for (i = 0; i < ctxt->states->nbState; i++) {
9946                        state = ctxt->states->tabState[i];
9947                        ctxt->state = state;
9948
9949                        if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
9950                            tmp = 0;
9951                            break;
9952                        }
9953                    }
9954                    if (tmp != 0) {
9955                        /*
9956                         * validation error, log the message for the "best" one
9957                         */
9958                        ctxt->flags |= FLAGS_IGNORABLE;
9959                        xmlRelaxNGLogBestError(ctxt);
9960                    }
9961                    for (i = 0; i < ctxt->states->nbState; i++) {
9962                        xmlRelaxNGFreeValidState(ctxt,
9963                                                 ctxt->states->tabState[i]);
9964                        ctxt->states->tabState[i] = NULL;
9965                    }
9966                    xmlRelaxNGFreeStates(ctxt, ctxt->states);
9967                    ctxt->flags = oldflags;
9968                    ctxt->states = NULL;
9969                    if ((ret == 0) && (tmp == -1))
9970                        ret = -1;
9971                } else {
9972                    state = ctxt->state;
9973                    if (ret == 0)
9974                        ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
9975                    xmlRelaxNGFreeValidState(ctxt, state);
9976                }
9977            }
9978            if (ret == 0) {
9979                node->psvi = define;
9980            }
9981            ctxt->flags = oldflags;
9982            ctxt->state = oldstate;
9983            if (oldstate != NULL)
9984                oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9985            if (ret != 0) {
9986                if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9987                    xmlRelaxNGDumpValidError(ctxt);
9988                    ret = 0;
9989#if 0
9990                } else {
9991                    ret = -2;
9992#endif
9993                }
9994            } else {
9995                if (ctxt->errNr > errNr)
9996                    xmlRelaxNGPopErrors(ctxt, errNr);
9997            }
9998
9999#ifdef DEBUG
10000            xmlGenericError(xmlGenericErrorContext,
10001                            "xmlRelaxNGValidateDefinition(): validated %s : %d",
10002                            node->name, ret);
10003            if (oldstate == NULL)
10004                xmlGenericError(xmlGenericErrorContext, ": no state\n");
10005            else if (oldstate->seq == NULL)
10006                xmlGenericError(xmlGenericErrorContext, ": done\n");
10007            else if (oldstate->seq->type == XML_ELEMENT_NODE)
10008                xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
10009                                oldstate->seq->name);
10010            else
10011                xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
10012                                oldstate->seq->name, oldstate->seq->type);
10013#endif
10014            break;
10015        case XML_RELAXNG_OPTIONAL:{
10016                errNr = ctxt->errNr;
10017                oldflags = ctxt->flags;
10018                ctxt->flags |= FLAGS_IGNORABLE;
10019                oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10020                ret =
10021                    xmlRelaxNGValidateDefinitionList(ctxt,
10022                                                     define->content);
10023                if (ret != 0) {
10024                    if (ctxt->state != NULL)
10025                        xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10026                    ctxt->state = oldstate;
10027                    ctxt->flags = oldflags;
10028                    ret = 0;
10029                    if (ctxt->errNr > errNr)
10030                        xmlRelaxNGPopErrors(ctxt, errNr);
10031                    break;
10032                }
10033                if (ctxt->states != NULL) {
10034                    xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10035                } else {
10036                    ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
10037                    if (ctxt->states == NULL) {
10038                        xmlRelaxNGFreeValidState(ctxt, oldstate);
10039                        ctxt->flags = oldflags;
10040                        ret = -1;
10041                        if (ctxt->errNr > errNr)
10042                            xmlRelaxNGPopErrors(ctxt, errNr);
10043                        break;
10044                    }
10045                    xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10046                    xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
10047                    ctxt->state = NULL;
10048                }
10049                ctxt->flags = oldflags;
10050                ret = 0;
10051                if (ctxt->errNr > errNr)
10052                    xmlRelaxNGPopErrors(ctxt, errNr);
10053                break;
10054            }
10055        case XML_RELAXNG_ONEORMORE:
10056            errNr = ctxt->errNr;
10057            ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10058            if (ret != 0) {
10059                break;
10060            }
10061            if (ctxt->errNr > errNr)
10062                xmlRelaxNGPopErrors(ctxt, errNr);
10063            /* no break on purpose */
10064        case XML_RELAXNG_ZEROORMORE:{
10065                int progress;
10066                xmlRelaxNGStatesPtr states = NULL, res = NULL;
10067                int base, j;
10068
10069                errNr = ctxt->errNr;
10070                res = xmlRelaxNGNewStates(ctxt, 1);
10071                if (res == NULL) {
10072                    ret = -1;
10073                    break;
10074                }
10075                /*
10076                 * All the input states are also exit states
10077                 */
10078                if (ctxt->state != NULL) {
10079                    xmlRelaxNGAddStates(ctxt, res,
10080                                        xmlRelaxNGCopyValidState(ctxt,
10081                                                                 ctxt->
10082                                                                 state));
10083                } else {
10084                    for (j = 0; j < ctxt->states->nbState; j++) {
10085                        xmlRelaxNGAddStates(ctxt, res,
10086                            xmlRelaxNGCopyValidState(ctxt,
10087                                            ctxt->states->tabState[j]));
10088                    }
10089                }
10090                oldflags = ctxt->flags;
10091                ctxt->flags |= FLAGS_IGNORABLE;
10092                do {
10093                    progress = 0;
10094                    base = res->nbState;
10095
10096                    if (ctxt->states != NULL) {
10097                        states = ctxt->states;
10098                        for (i = 0; i < states->nbState; i++) {
10099                            ctxt->state = states->tabState[i];
10100                            ctxt->states = NULL;
10101                            ret = xmlRelaxNGValidateDefinitionList(ctxt,
10102                                                                   define->
10103                                                                   content);
10104                            if (ret == 0) {
10105                                if (ctxt->state != NULL) {
10106                                    tmp = xmlRelaxNGAddStates(ctxt, res,
10107                                                              ctxt->state);
10108                                    ctxt->state = NULL;
10109                                    if (tmp == 1)
10110                                        progress = 1;
10111                                } else if (ctxt->states != NULL) {
10112                                    for (j = 0; j < ctxt->states->nbState;
10113                                         j++) {
10114                                        tmp =
10115                                            xmlRelaxNGAddStates(ctxt, res,
10116                                                   ctxt->states->tabState[j]);
10117                                        if (tmp == 1)
10118                                            progress = 1;
10119                                    }
10120                                    xmlRelaxNGFreeStates(ctxt,
10121                                                         ctxt->states);
10122                                    ctxt->states = NULL;
10123                                }
10124                            } else {
10125                                if (ctxt->state != NULL) {
10126                                    xmlRelaxNGFreeValidState(ctxt,
10127                                                             ctxt->state);
10128                                    ctxt->state = NULL;
10129                                }
10130                            }
10131                        }
10132                    } else {
10133                        ret = xmlRelaxNGValidateDefinitionList(ctxt,
10134                                                               define->
10135                                                               content);
10136                        if (ret != 0) {
10137                            xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10138                            ctxt->state = NULL;
10139                        } else {
10140                            base = res->nbState;
10141                            if (ctxt->state != NULL) {
10142                                tmp = xmlRelaxNGAddStates(ctxt, res,
10143                                                          ctxt->state);
10144                                ctxt->state = NULL;
10145                                if (tmp == 1)
10146                                    progress = 1;
10147                            } else if (ctxt->states != NULL) {
10148                                for (j = 0; j < ctxt->states->nbState; j++) {
10149                                    tmp = xmlRelaxNGAddStates(ctxt, res,
10150                                               ctxt->states->tabState[j]);
10151                                    if (tmp == 1)
10152                                        progress = 1;
10153                                }
10154                                if (states == NULL) {
10155                                    states = ctxt->states;
10156                                } else {
10157                                    xmlRelaxNGFreeStates(ctxt,
10158                                                         ctxt->states);
10159                                }
10160                                ctxt->states = NULL;
10161                            }
10162                        }
10163                    }
10164                    if (progress) {
10165                        /*
10166                         * Collect all the new nodes added at that step
10167                         * and make them the new node set
10168                         */
10169                        if (res->nbState - base == 1) {
10170                            ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10171                                                                   res->
10172                                                                   tabState
10173                                                                   [base]);
10174                        } else {
10175                            if (states == NULL) {
10176                                xmlRelaxNGNewStates(ctxt,
10177                                                    res->nbState - base);
10178			        states = ctxt->states;
10179				if (states == NULL) {
10180				    progress = 0;
10181				    break;
10182				}
10183                            }
10184                            states->nbState = 0;
10185                            for (i = base; i < res->nbState; i++)
10186                                xmlRelaxNGAddStates(ctxt, states,
10187                                                    xmlRelaxNGCopyValidState
10188                                                    (ctxt, res->tabState[i]));
10189                            ctxt->states = states;
10190                        }
10191                    }
10192                } while (progress == 1);
10193                if (states != NULL) {
10194                    xmlRelaxNGFreeStates(ctxt, states);
10195                }
10196                ctxt->states = res;
10197                ctxt->flags = oldflags;
10198#if 0
10199                /*
10200                 * errors may have to be propagated back...
10201                 */
10202                if (ctxt->errNr > errNr)
10203                    xmlRelaxNGPopErrors(ctxt, errNr);
10204#endif
10205                ret = 0;
10206                break;
10207            }
10208        case XML_RELAXNG_CHOICE:{
10209                xmlRelaxNGDefinePtr list = NULL;
10210                xmlRelaxNGStatesPtr states = NULL;
10211
10212                node = xmlRelaxNGSkipIgnored(ctxt, node);
10213
10214                errNr = ctxt->errNr;
10215                if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10216		    (node != NULL)) {
10217		    /*
10218		     * node == NULL can't be optimized since IS_TRIABLE
10219		     * doesn't account for choice which may lead to
10220		     * only attributes.
10221		     */
10222                    xmlHashTablePtr triage =
10223                        (xmlHashTablePtr) define->data;
10224
10225                    /*
10226                     * Something we can optimize cleanly there is only one
10227                     * possble branch out !
10228                     */
10229                    if ((node->type == XML_TEXT_NODE) ||
10230                        (node->type == XML_CDATA_SECTION_NODE)) {
10231                        list =
10232                            xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10233                    } else if (node->type == XML_ELEMENT_NODE) {
10234                        if (node->ns != NULL) {
10235                            list = xmlHashLookup2(triage, node->name,
10236                                                  node->ns->href);
10237                            if (list == NULL)
10238                                list =
10239                                    xmlHashLookup2(triage, BAD_CAST "#any",
10240                                                   node->ns->href);
10241                        } else
10242                            list =
10243                                xmlHashLookup2(triage, node->name, NULL);
10244                        if (list == NULL)
10245                            list =
10246                                xmlHashLookup2(triage, BAD_CAST "#any",
10247                                               NULL);
10248                    }
10249                    if (list == NULL) {
10250                        ret = -1;
10251			VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
10252                        break;
10253                    }
10254                    ret = xmlRelaxNGValidateDefinition(ctxt, list);
10255                    if (ret == 0) {
10256                    }
10257                    break;
10258                }
10259
10260                list = define->content;
10261                oldflags = ctxt->flags;
10262                ctxt->flags |= FLAGS_IGNORABLE;
10263
10264                while (list != NULL) {
10265                    oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10266                    ret = xmlRelaxNGValidateDefinition(ctxt, list);
10267                    if (ret == 0) {
10268                        if (states == NULL) {
10269                            states = xmlRelaxNGNewStates(ctxt, 1);
10270                        }
10271                        if (ctxt->state != NULL) {
10272                            xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10273                        } else if (ctxt->states != NULL) {
10274                            for (i = 0; i < ctxt->states->nbState; i++) {
10275                                xmlRelaxNGAddStates(ctxt, states,
10276                                                    ctxt->states->
10277                                                    tabState[i]);
10278                            }
10279                            xmlRelaxNGFreeStates(ctxt, ctxt->states);
10280                            ctxt->states = NULL;
10281                        }
10282                    } else {
10283                        xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10284                    }
10285                    ctxt->state = oldstate;
10286                    list = list->next;
10287                }
10288                if (states != NULL) {
10289                    xmlRelaxNGFreeValidState(ctxt, oldstate);
10290                    ctxt->states = states;
10291                    ctxt->state = NULL;
10292                    ret = 0;
10293                } else {
10294                    ctxt->states = NULL;
10295                }
10296                ctxt->flags = oldflags;
10297                if (ret != 0) {
10298                    if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10299                        xmlRelaxNGDumpValidError(ctxt);
10300                    }
10301                } else {
10302                    if (ctxt->errNr > errNr)
10303                        xmlRelaxNGPopErrors(ctxt, errNr);
10304                }
10305                break;
10306            }
10307        case XML_RELAXNG_DEF:
10308        case XML_RELAXNG_GROUP:
10309            ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10310            break;
10311        case XML_RELAXNG_INTERLEAVE:
10312            ret = xmlRelaxNGValidateInterleave(ctxt, define);
10313            break;
10314        case XML_RELAXNG_ATTRIBUTE:
10315            ret = xmlRelaxNGValidateAttribute(ctxt, define);
10316            break;
10317        case XML_RELAXNG_START:
10318        case XML_RELAXNG_NOOP:
10319        case XML_RELAXNG_REF:
10320        case XML_RELAXNG_EXTERNALREF:
10321        case XML_RELAXNG_PARENTREF:
10322            ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10323            break;
10324        case XML_RELAXNG_DATATYPE:{
10325                xmlNodePtr child;
10326                xmlChar *content = NULL;
10327
10328                child = node;
10329                while (child != NULL) {
10330                    if (child->type == XML_ELEMENT_NODE) {
10331                        VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10332                                   node->parent->name);
10333                        ret = -1;
10334                        break;
10335                    } else if ((child->type == XML_TEXT_NODE) ||
10336                               (child->type == XML_CDATA_SECTION_NODE)) {
10337                        content = xmlStrcat(content, child->content);
10338                    }
10339                    /* TODO: handle entities ... */
10340                    child = child->next;
10341                }
10342                if (ret == -1) {
10343                    if (content != NULL)
10344                        xmlFree(content);
10345                    break;
10346                }
10347                if (content == NULL) {
10348                    content = xmlStrdup(BAD_CAST "");
10349                    if (content == NULL) {
10350                        xmlRngVErrMemory(ctxt, "validating\n");
10351                        ret = -1;
10352                        break;
10353                    }
10354                }
10355                ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10356                                                 ctxt->state->seq);
10357                if (ret == -1) {
10358                    VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10359                } else if (ret == 0) {
10360                    ctxt->state->seq = NULL;
10361                }
10362                if (content != NULL)
10363                    xmlFree(content);
10364                break;
10365            }
10366        case XML_RELAXNG_VALUE:{
10367                xmlChar *content = NULL;
10368                xmlChar *oldvalue;
10369                xmlNodePtr child;
10370
10371                child = node;
10372                while (child != NULL) {
10373                    if (child->type == XML_ELEMENT_NODE) {
10374                        VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10375                                   node->parent->name);
10376                        ret = -1;
10377                        break;
10378                    } else if ((child->type == XML_TEXT_NODE) ||
10379                               (child->type == XML_CDATA_SECTION_NODE)) {
10380                        content = xmlStrcat(content, child->content);
10381                    }
10382                    /* TODO: handle entities ... */
10383                    child = child->next;
10384                }
10385                if (ret == -1) {
10386                    if (content != NULL)
10387                        xmlFree(content);
10388                    break;
10389                }
10390                if (content == NULL) {
10391                    content = xmlStrdup(BAD_CAST "");
10392                    if (content == NULL) {
10393                        xmlRngVErrMemory(ctxt, "validating\n");
10394                        ret = -1;
10395                        break;
10396                    }
10397                }
10398                oldvalue = ctxt->state->value;
10399                ctxt->state->value = content;
10400                ret = xmlRelaxNGValidateValue(ctxt, define);
10401                ctxt->state->value = oldvalue;
10402                if (ret == -1) {
10403                    VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10404                } else if (ret == 0) {
10405                    ctxt->state->seq = NULL;
10406                }
10407                if (content != NULL)
10408                    xmlFree(content);
10409                break;
10410            }
10411        case XML_RELAXNG_LIST:{
10412                xmlChar *content;
10413                xmlNodePtr child;
10414                xmlChar *oldvalue, *oldendvalue;
10415                int len;
10416
10417                /*
10418                 * Make sure it's only text nodes
10419                 */
10420
10421                content = NULL;
10422                child = node;
10423                while (child != NULL) {
10424                    if (child->type == XML_ELEMENT_NODE) {
10425                        VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10426                                   node->parent->name);
10427                        ret = -1;
10428                        break;
10429                    } else if ((child->type == XML_TEXT_NODE) ||
10430                               (child->type == XML_CDATA_SECTION_NODE)) {
10431                        content = xmlStrcat(content, child->content);
10432                    }
10433                    /* TODO: handle entities ... */
10434                    child = child->next;
10435                }
10436                if (ret == -1) {
10437                    if (content != NULL)
10438                        xmlFree(content);
10439                    break;
10440                }
10441                if (content == NULL) {
10442                    content = xmlStrdup(BAD_CAST "");
10443                    if (content == NULL) {
10444                        xmlRngVErrMemory(ctxt, "validating\n");
10445                        ret = -1;
10446                        break;
10447                    }
10448                }
10449                len = xmlStrlen(content);
10450                oldvalue = ctxt->state->value;
10451                oldendvalue = ctxt->state->endvalue;
10452                ctxt->state->value = content;
10453                ctxt->state->endvalue = content + len;
10454                ret = xmlRelaxNGValidateValue(ctxt, define);
10455                ctxt->state->value = oldvalue;
10456                ctxt->state->endvalue = oldendvalue;
10457                if (ret == -1) {
10458                    VALID_ERR(XML_RELAXNG_ERR_LIST);
10459                } else if ((ret == 0) && (node != NULL)) {
10460                    ctxt->state->seq = node->next;
10461                }
10462                if (content != NULL)
10463                    xmlFree(content);
10464                break;
10465            }
10466        case XML_RELAXNG_EXCEPT:
10467        case XML_RELAXNG_PARAM:
10468            TODO ret = -1;
10469            break;
10470    }
10471    ctxt->depth--;
10472#ifdef DEBUG
10473    for (i = 0; i < ctxt->depth; i++)
10474        xmlGenericError(xmlGenericErrorContext, " ");
10475    xmlGenericError(xmlGenericErrorContext,
10476                    "Validating %s ", xmlRelaxNGDefName(define));
10477    if (define->name != NULL)
10478        xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
10479    if (ret == 0)
10480        xmlGenericError(xmlGenericErrorContext, "suceeded\n");
10481    else
10482        xmlGenericError(xmlGenericErrorContext, "failed\n");
10483#endif
10484    return (ret);
10485}
10486
10487/**
10488 * xmlRelaxNGValidateDefinition:
10489 * @ctxt:  a Relax-NG validation context
10490 * @define:  the definition to verify
10491 *
10492 * Validate the current node lists against the definition
10493 *
10494 * Returns 0 if the validation succeeded or an error code.
10495 */
10496static int
10497xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10498                             xmlRelaxNGDefinePtr define)
10499{
10500    xmlRelaxNGStatesPtr states, res;
10501    int i, j, k, ret, oldflags;
10502
10503    /*
10504     * We should NOT have both ctxt->state and ctxt->states
10505     */
10506    if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10507        TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10508        ctxt->state = NULL;
10509    }
10510
10511    if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10512        if (ctxt->states != NULL) {
10513            ctxt->state = ctxt->states->tabState[0];
10514            xmlRelaxNGFreeStates(ctxt, ctxt->states);
10515            ctxt->states = NULL;
10516        }
10517        ret = xmlRelaxNGValidateState(ctxt, define);
10518        if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10519            TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10520            ctxt->state = NULL;
10521        }
10522        if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10523            ctxt->state = ctxt->states->tabState[0];
10524            xmlRelaxNGFreeStates(ctxt, ctxt->states);
10525            ctxt->states = NULL;
10526        }
10527        return (ret);
10528    }
10529
10530    states = ctxt->states;
10531    ctxt->states = NULL;
10532    res = NULL;
10533    j = 0;
10534    oldflags = ctxt->flags;
10535    ctxt->flags |= FLAGS_IGNORABLE;
10536    for (i = 0; i < states->nbState; i++) {
10537        ctxt->state = states->tabState[i];
10538        ctxt->states = NULL;
10539        ret = xmlRelaxNGValidateState(ctxt, define);
10540        /*
10541         * We should NOT have both ctxt->state and ctxt->states
10542         */
10543        if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10544            TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10545            ctxt->state = NULL;
10546        }
10547        if (ret == 0) {
10548            if (ctxt->states == NULL) {
10549                if (res != NULL) {
10550                    /* add the state to the container */
10551                    xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10552                    ctxt->state = NULL;
10553                } else {
10554                    /* add the state directly in states */
10555                    states->tabState[j++] = ctxt->state;
10556                    ctxt->state = NULL;
10557                }
10558            } else {
10559                if (res == NULL) {
10560                    /* make it the new container and copy other results */
10561                    res = ctxt->states;
10562                    ctxt->states = NULL;
10563                    for (k = 0; k < j; k++)
10564                        xmlRelaxNGAddStates(ctxt, res,
10565                                            states->tabState[k]);
10566                } else {
10567                    /* add all the new results to res and reff the container */
10568                    for (k = 0; k < ctxt->states->nbState; k++)
10569                        xmlRelaxNGAddStates(ctxt, res,
10570                                            ctxt->states->tabState[k]);
10571                    xmlRelaxNGFreeStates(ctxt, ctxt->states);
10572                    ctxt->states = NULL;
10573                }
10574            }
10575        } else {
10576            if (ctxt->state != NULL) {
10577                xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10578                ctxt->state = NULL;
10579            } else if (ctxt->states != NULL) {
10580                for (k = 0; k < ctxt->states->nbState; k++)
10581                    xmlRelaxNGFreeValidState(ctxt,
10582                                             ctxt->states->tabState[k]);
10583                xmlRelaxNGFreeStates(ctxt, ctxt->states);
10584                ctxt->states = NULL;
10585            }
10586        }
10587    }
10588    ctxt->flags = oldflags;
10589    if (res != NULL) {
10590        xmlRelaxNGFreeStates(ctxt, states);
10591        ctxt->states = res;
10592        ret = 0;
10593    } else if (j > 1) {
10594        states->nbState = j;
10595        ctxt->states = states;
10596        ret = 0;
10597    } else if (j == 1) {
10598        ctxt->state = states->tabState[0];
10599        xmlRelaxNGFreeStates(ctxt, states);
10600        ret = 0;
10601    } else {
10602        ret = -1;
10603        xmlRelaxNGFreeStates(ctxt, states);
10604        if (ctxt->states != NULL) {
10605            xmlRelaxNGFreeStates(ctxt, ctxt->states);
10606            ctxt->states = NULL;
10607        }
10608    }
10609    if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10610        TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10611        ctxt->state = NULL;
10612    }
10613    return (ret);
10614}
10615
10616/**
10617 * xmlRelaxNGValidateDocument:
10618 * @ctxt:  a Relax-NG validation context
10619 * @doc:  the document
10620 *
10621 * Validate the given document
10622 *
10623 * Returns 0 if the validation succeeded or an error code.
10624 */
10625static int
10626xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10627{
10628    int ret;
10629    xmlRelaxNGPtr schema;
10630    xmlRelaxNGGrammarPtr grammar;
10631    xmlRelaxNGValidStatePtr state;
10632    xmlNodePtr node;
10633
10634    if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10635        return (-1);
10636
10637    ctxt->errNo = XML_RELAXNG_OK;
10638    schema = ctxt->schema;
10639    grammar = schema->topgrammar;
10640    if (grammar == NULL) {
10641        VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10642        return (-1);
10643    }
10644    state = xmlRelaxNGNewValidState(ctxt, NULL);
10645    ctxt->state = state;
10646    ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
10647    if ((ctxt->state != NULL) && (state->seq != NULL)) {
10648        state = ctxt->state;
10649        node = state->seq;
10650        node = xmlRelaxNGSkipIgnored(ctxt, node);
10651        if (node != NULL) {
10652            if (ret != -1) {
10653                VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10654                ret = -1;
10655            }
10656        }
10657    } else if (ctxt->states != NULL) {
10658        int i;
10659        int tmp = -1;
10660
10661        for (i = 0; i < ctxt->states->nbState; i++) {
10662            state = ctxt->states->tabState[i];
10663            node = state->seq;
10664            node = xmlRelaxNGSkipIgnored(ctxt, node);
10665            if (node == NULL)
10666                tmp = 0;
10667            xmlRelaxNGFreeValidState(ctxt, state);
10668        }
10669        if (tmp == -1) {
10670            if (ret != -1) {
10671                VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10672                ret = -1;
10673            }
10674        }
10675    }
10676    if (ctxt->state != NULL) {
10677        xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10678        ctxt->state = NULL;
10679    }
10680    if (ret != 0)
10681        xmlRelaxNGDumpValidError(ctxt);
10682#ifdef DEBUG
10683    else if (ctxt->errNr != 0) {
10684        ctxt->error(ctxt->userData,
10685                    "%d Extra error messages left on stack !\n",
10686                    ctxt->errNr);
10687        xmlRelaxNGDumpValidError(ctxt);
10688    }
10689#endif
10690#ifdef LIBXML_VALID_ENABLED
10691    if (ctxt->idref == 1) {
10692        xmlValidCtxt vctxt;
10693
10694        memset(&vctxt, 0, sizeof(xmlValidCtxt));
10695        vctxt.valid = 1;
10696        vctxt.error = ctxt->error;
10697        vctxt.warning = ctxt->warning;
10698        vctxt.userData = ctxt->userData;
10699
10700        if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10701            ret = -1;
10702    }
10703#endif /* LIBXML_VALID_ENABLED */
10704    if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10705        ret = -1;
10706
10707    return (ret);
10708}
10709
10710/************************************************************************
10711 * 									*
10712 * 			Validation interfaces				*
10713 * 									*
10714 ************************************************************************/
10715
10716/**
10717 * xmlRelaxNGNewValidCtxt:
10718 * @schema:  a precompiled XML RelaxNGs
10719 *
10720 * Create an XML RelaxNGs validation context based on the given schema
10721 *
10722 * Returns the validation context or NULL in case of error
10723 */
10724xmlRelaxNGValidCtxtPtr
10725xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10726{
10727    xmlRelaxNGValidCtxtPtr ret;
10728
10729    ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10730    if (ret == NULL) {
10731        xmlRngVErrMemory(NULL, "building context\n");
10732        return (NULL);
10733    }
10734    memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10735    ret->schema = schema;
10736    ret->error = xmlGenericError;
10737    ret->userData = xmlGenericErrorContext;
10738    ret->errNr = 0;
10739    ret->errMax = 0;
10740    ret->err = NULL;
10741    ret->errTab = NULL;
10742    if (schema != NULL)
10743	ret->idref = schema->idref;
10744    ret->states = NULL;
10745    ret->freeState = NULL;
10746    ret->freeStates = NULL;
10747    ret->errNo = XML_RELAXNG_OK;
10748    return (ret);
10749}
10750
10751/**
10752 * xmlRelaxNGFreeValidCtxt:
10753 * @ctxt:  the schema validation context
10754 *
10755 * Free the resources associated to the schema validation context
10756 */
10757void
10758xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10759{
10760    int k;
10761
10762    if (ctxt == NULL)
10763        return;
10764    if (ctxt->states != NULL)
10765        xmlRelaxNGFreeStates(NULL, ctxt->states);
10766    if (ctxt->freeState != NULL) {
10767        for (k = 0; k < ctxt->freeState->nbState; k++) {
10768            xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10769        }
10770        xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10771    }
10772    if (ctxt->freeStates != NULL) {
10773        for (k = 0; k < ctxt->freeStatesNr; k++) {
10774            xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10775        }
10776        xmlFree(ctxt->freeStates);
10777    }
10778    if (ctxt->errTab != NULL)
10779        xmlFree(ctxt->errTab);
10780    if (ctxt->elemTab != NULL) {
10781        xmlRegExecCtxtPtr exec;
10782
10783        exec = xmlRelaxNGElemPop(ctxt);
10784        while (exec != NULL) {
10785            xmlRegFreeExecCtxt(exec);
10786            exec = xmlRelaxNGElemPop(ctxt);
10787        }
10788        xmlFree(ctxt->elemTab);
10789    }
10790    xmlFree(ctxt);
10791}
10792
10793/**
10794 * xmlRelaxNGSetValidErrors:
10795 * @ctxt:  a Relax-NG validation context
10796 * @err:  the error function
10797 * @warn: the warning function
10798 * @ctx: the functions context
10799 *
10800 * Set the error and warning callback informations
10801 */
10802void
10803xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10804                         xmlRelaxNGValidityErrorFunc err,
10805                         xmlRelaxNGValidityWarningFunc warn, void *ctx)
10806{
10807    if (ctxt == NULL)
10808        return;
10809    ctxt->error = err;
10810    ctxt->warning = warn;
10811    ctxt->userData = ctx;
10812    ctxt->serror = NULL;
10813}
10814
10815/**
10816 * xmlRelaxNGSetValidStructuredErrors:
10817 * @ctxt:  a Relax-NG validation context
10818 * @serror:  the structured error function
10819 * @ctx: the functions context
10820 *
10821 * Set the structured error callback
10822 */
10823void
10824xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
10825                                   xmlStructuredErrorFunc serror, void *ctx)
10826{
10827    if (ctxt == NULL)
10828        return;
10829    ctxt->serror = serror;
10830    ctxt->error = NULL;
10831    ctxt->warning = NULL;
10832    ctxt->userData = ctx;
10833}
10834
10835/**
10836 * xmlRelaxNGGetValidErrors:
10837 * @ctxt:  a Relax-NG validation context
10838 * @err:  the error function result
10839 * @warn: the warning function result
10840 * @ctx: the functions context result
10841 *
10842 * Get the error and warning callback informations
10843 *
10844 * Returns -1 in case of error and 0 otherwise
10845 */
10846int
10847xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10848                         xmlRelaxNGValidityErrorFunc * err,
10849                         xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10850{
10851    if (ctxt == NULL)
10852        return (-1);
10853    if (err != NULL)
10854        *err = ctxt->error;
10855    if (warn != NULL)
10856        *warn = ctxt->warning;
10857    if (ctx != NULL)
10858        *ctx = ctxt->userData;
10859    return (0);
10860}
10861
10862/**
10863 * xmlRelaxNGValidateDoc:
10864 * @ctxt:  a Relax-NG validation context
10865 * @doc:  a parsed document tree
10866 *
10867 * Validate a document tree in memory.
10868 *
10869 * Returns 0 if the document is valid, a positive error code
10870 *     number otherwise and -1 in case of internal or API error.
10871 */
10872int
10873xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10874{
10875    int ret;
10876
10877    if ((ctxt == NULL) || (doc == NULL))
10878        return (-1);
10879
10880    ctxt->doc = doc;
10881
10882    ret = xmlRelaxNGValidateDocument(ctxt, doc);
10883    /*
10884     * TODO: build error codes
10885     */
10886    if (ret == -1)
10887        return (1);
10888    return (ret);
10889}
10890
10891#define bottom_relaxng
10892#include "elfgcchack.h"
10893#endif /* LIBXML_SCHEMAS_ENABLED */
10894