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